I have been doing TDD for about two years now and using mock testing for interaction based unit testing in my projects. What I have learned over this time is, a unit testable design leads to introduction of interfaces and dependency injection for testing a code in isolation. And when I want to perform tests on my interactions, I need to create mock objects and inject these mock instances to my object under test. Sometimes, a unit test class needs to create quite a few of such mock objects and I feel this can be done using a simple wrapper around the usual mocking frameworks.
I suggest a similar and even more powerful wrapper so that you don't need to create instances for each of the mock objects, rather do it in a single call for all your desired mocks. I have shown this method for NMock2, however, its evident that you can write your own method for your favorite mocking framework just using this code as a reference.
This code is written in C# 3.0 and should compile in .Net 3.5. You will need to add a reference to NMock2 to compile this. Also, you need to know a bit about Reflection to understand the following code fragment.
Disclaimer: This code is just a simple example and it may not suit all your needs.
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Reflection;
6
7
8 namespace NMock2.Extensions
9 {
10 public static class MockeryExtensions
11 {
12 /// <summary>
13 /// This method will fill all properties of the 'target' of interface type having a setter
14 /// </summary>
15 /// <param name="mocks"></param>
16 /// <param name="target"></param>
17 public static void FillWithMocks(this Mockery mocks, object target)
18 {
19 Type targetType = target.GetType();
20 PropertyInfo []properties = target.GetType().GetProperties();
21
22 foreach (PropertyInfo property in properties)
23 {
24 Type ptype = property.PropertyType;
25 if (ptype.IsInterface)
26 {
27 if(targetType.GetMethod(string.Format("set_{0}", property.Name)) != null)
28 {
29 targetType.GetProperty(property.Name).SetValue(target, mocks.NewMock(ptype), new object[] { });
30 }
31 }
32 }
33 }
34
35 /// <summary>
36 /// This method will fill the properties with names specified in the propertyNames array having a setter
37 /// </summary>
38 /// <param name="mocks"></param>
39 /// <param name="target"></param>
40 /// <param name="propertyNames"></param>
41 public static void FillWithMocks(this Mockery mocks, object target, params string[] propertyNames)
42 {
43 Type targetType = target.GetType();
44 foreach (string propertyName in propertyNames)
45 {
46 PropertyInfo pInfo = targetType.GetProperty(propertyName);
47 if (pInfo != null && targetType.GetMethod(string.Format("set_{0}", propertyName)) != null)
48 {
49 pInfo.SetValue(target, mocks.NewMock(pInfo.PropertyType), null);
50 }
51 else
52 {
53 throw new ArgumentException(string.Format("the property {0} is not found or does not have a setter", pInfo.Name));
54 }
55 }
56 }
57 }
58 }
So, with this extension method in place, you can go and write your test code in a much compact manner. The following is an example showing one possible use of this method in your NUnit test code.
83 public interface IMyInterface
84 {
85 void MyMethod(string name);
86 }
87
88 public class MyExampleClass
89 {
90 public IMyInterface MyPropertyOne
91 {
92 get;
93 set;
94 }
95
96 public IMyInterface MyPropertyTwo
97 {
98 get;
99 set;
100 }
101
102 public IMyInterface MyPropertyThree
103 {
104 get;
105 set;
106 }
107
108 public MyExampleClass()
109 {
110
111 }
112 }
113
114 [TestFixture]
115 public class MyExampleClassTest
116 {
117 private MyExampleClass _myExampleClass;
118 private Mockery _mocks;
119
120 [SetUp]
121 public void Init()
122 {
123 _myExampleClass = new MyExampleClass();
124 _mocks = new Mockery();
125
126 //This call fills all the three properties with mocks
127 _mocks.FillWithMocks(_myExampleClass);
128
129 //This call fills only MyPropertyOne and MyPropertyTwo with mocks
130 _mocks.FillWithMocks(_myExampleClass, "MyPropertyOne", "MyPropertyTwo");
131 }
132 }
Comments are welcome!