One of the new features in our new release 4.2 is the ability to mock fields. Since we have published this new feature we were asked several times why this was added.
Actually, there are several answers to this, but in this post I would like to focus on the least obvious one.
Part of our process here in Typemock (which we try to make as agile as possible) is periodically going over all our users feedback and looking for common cases that we can and solve by adding new functionality. When doing so for the 4.20 version we saw a relative large number of cases in which users tests failed when accessing fields on objects which were mocked.
here’s an example (simplified of course):
1 |
<span class="kwrd">public</span> <span class="kwrd">class</span> UsedClass<br />{<br /> <span class="kwrd">public</span> <span class="kwrd">int</span> ReturnFive()<br /> {<br /> <span class="kwrd">return</span> 5;<br /> }<br />}<br /><span class="kwrd">public</span> <span class="kwrd">class</span> UnderTest<br />{<br /> <span class="kwrd">private</span> UsedClass _usedInstance;<br /><br /> <span class="kwrd">public</span> UnderTest()<br /> {<br /> _usedInstance = <span class="kwrd">new</span> UsedClass();<br /> }<br /><br /> <span class="kwrd">public</span> <span class="kwrd">void</span> Initialize()<br /> {<br /> <span class="rem">//do some complex stuff we wish to mock in our tests </span><br /> }<br /><br /> <span class="kwrd">public</span> <span class="kwrd">int</span> Calculate(<span class="kwrd">int</span> num)<br /> {<br /> Initialize();<br /> <span class="kwrd">return</span> _usedInstance.ReturnFive() * num;<br /> }<br />}<br /><br />[TestMethod]<br />[VerifyMocks]<br /><span class="kwrd">public</span> <span class="kwrd">void</span> FailingTest()<br />{<br /> <span class="kwrd">using</span> (RecordExpectations rec = <span class="kwrd">new</span> RecordExpectations())<br /> {<br /> UnderTest mock = <span class="kwrd">new</span> UnderTest();<br /> mock.Initialize();<br /> }<br /> UnderTest target = <span class="kwrd">new</span> UnderTest();<br /> <span class="kwrd">int</span> actual = target.Calculate(6);<br /> Assert.AreEqual(30, actual);<br />} |
Running this example with previous versions of the Isolator resulted in a NullReferanceError being thrown from target.Calculate(6). It is thrown because by default the Isolator mocks calls for constructors on mocked objects. Therefore the actual initialization of the _usedInstance is skipped during the test, leaving it as null when calling the Calculate method.
Surprisingly, this kind of defect is quite hard to locate especially if the call to the fields is hidden inside several layers of code.
So how does this relates to Field Mocking?
When using the Natural Mocks syntax, we automatically attach mock controllers to all instance fields of mocked instances (and for all static fields on mocked classes) created inside the recording block. This gives us the ability to detect that calls are issues on fields which has no real value and in these cases we throw the following exception:
TypeMock.VerifyException: TypeMock Verification: The call to UsedClass.ReturnFive() was made on an uninitialized field.
Hopefully this exception will be much more helpful and will save frustrating debugging time when actually encountering this.
However, this has its price. Values of fields of mocked instances are no longer equal to null, which does affect application logic if somewhere inside the code fields are compared to null, (during lazy loading for example).
However, we do feel that this price is minor and most people will not encounter this ill affect but just in case we added the ability to change this default behavior and instruct the recorder to ignore fields this can be done by setting the RecordExpectations.DefaultBehavior.AutomaticFieldMocking to false.
The other main reason for adding this feature is that it is useful.
There are cases in which people wants to mock a fields without the need to implement some sort of bypassing mechanisms (singleton mocking is a good example for it).