Guest post by Lior Friedman.
Interaction testing is a common type of unit testing. In this type of tests, one checks that a specific unit “interacts” with another way according to an agreed protocol, usually this protocol is embodied in the used class API. Its in interaction tests that mocking framework becomes real handy.
Let’s do an example.
I have a system, which tracks my schedule. It publishes a certain API that enable to ask me to do things. However,internally it works asynchronously. When it receives a request, it verifies that it can handle the request. If this condition is met, it issues a request on a message queue in order to switch the execution content (and handle the details with the request).
In order to keep the example simple I’ll ignore the need to return an answer from the requested execution.
Here’s a simple example of such an API method:
1 |
<span style="color: blue">public bool </span>PickKidsFromSchool(<span style="color: #2b91af">DateTime </span>onDate)<br />{<br /> <span style="color: blue">if </span>(TooFarInThFuture(onDate))<br /> {<br /> <span style="color: blue">return false</span>;<br /> }<br /> <span style="color: blue">if </span>(!Free(onDate)<br /> && CantMoveAppointments(onDate) )<br /> {<br /> <span style="color: blue">return false</span>;<br /> }<br /> <span style="color: blue">var </span>request = <span style="color: blue">new </span><span style="color: #2b91af">PickKidsRequest</span>(onDate);<br /> _RequestQueue.Enqueue(request);<br /> <span style="color: blue">return true</span>;<br />} |
And here’s the logic in charge of the actual handling of the message:
1 |
<span style="color: blue">public void </span>HandleRequest(<span style="color: #2b91af">MySchedule </span>Scheduler)<br />{<br /> Scheduler.FreeTime(<br /> SCHOOL_END_TIME, <br /> <span style="color: #2b91af">MySchedule</span>.Evening);<br /> <br /> <span style="color: #2b91af">Appointment </span>appointment = <br /> <span style="color: blue">new </span><span style="color: #2b91af">Appointment</span>(<span style="color: #a31515">"Pick kids"</span>);<br /><br /> Scheduler.SetAppointment(<br /> appointment, <br /> _RequestDate, <br /> SCHOOL_END_TIME);<br />} |
There are several ways to tackle testing of such a component. My preferred way is to split the problem into two main parts (and a smaller hidden one) and test each part separately: The first part is to test the handling logic (HandleRequest) , i.e. after the message was taken from the queue. The second part is to test API method (PickKidsFromSchool), making sure it does the proper verification, and at the end issue “enqueue” the proper message on the queue. We’re not going to talk about those today.
The “hidden” part is to verify that the queuing mechanism itself is working properly. Specifically, we need to make sure we’re able to pass a message to and from the queue to the appropriate handler.
Here’s how I use Isolator in order to verify specific calls, and how it allows me to test the second part.
Here is the test:
1 |
[<span style="color: #2b91af">TestMethod</span>()]<br />[<span style="color: #2b91af">Isolated</span>]<br /><span style="color: blue">public void </span>PickKids_HasTime_EnqueRequest()<br />{<br /> <span style="color: blue">var </span>fakeQueue = <br /> <span style="color: #2b91af">Isolate</span>.Fake.Instance<<span style="color: #2b91af">Queue</span><<span style="color: #2b91af">Requests</span>>>();<br /> <span style="color: #2b91af">DateTime </span>onDate = <span style="color: blue">new </span><span style="color: #2b91af">DateTime</span>(2010, 8, 10);<br /><br /> <span style="color: blue">var </span>target = <span style="color: blue">new </span><span style="color: #2b91af">MySchedule</span>(fakeQueue);<br /> target.PickKidsFromSchool(onDate);<br /> <br /> <span style="color: blue">var </span>expectedRequest = <br /> <span style="color: blue">new </span><span style="color: #2b91af">PickKidsRequest</span>(onDate);<br /> <span style="color: #2b91af">Isolate</span>.Verify.WasCalledWithExactArguments<br /> (() => fakeQueue.Enqueue(expectedRequest));<br /><br />} |
The interesting line is the last line of the test:
1 |
<span style="color: #2b91af">Isolate</span>.Verify.WasCalledWithExactArguments<br /> (() => fakeQueue.Enqueue(expectedRequest)); |
This statement verifies that a message was sent to the queue, and also verifies that the sent message matches the expected message supplied. The test fails if neither of these conditions are met.
Similarly I can use the following statement to verify that a message was not queued, which is necessary to test cases that reject the request.
1 |
<span style="color: #2b91af">Isolate</span>.Verify.WasNotCalled<br /> (() => fakeQueue.Enqueue(<span style="color: blue">null</span>)); |
In conclusion: because our code interacts with other pieces, we need to know it calls them, and does so correctly. With Verify it’s easy to set the pass/fail criterion for interaction, and make sure the correct call on the dependency was made.