Well, it’s been a while since I’ve gone back to basics. But let’s do that, shall we? Why do we need isolation anyway? Step into my time machine, will you?
It was about 4 years ago, when I decided to try TDD (Test Driven Development). I was a project manager at the time, and I had a rule – never test anything on your team, before you try it (on) yourself. I was writing a communication server at the time, and thought – hey, why not?
Starting was easy. I added a couple of interfaces, checked that the object is created correctly. And then I got to the heart of the matter – the component used MSMQ as a messaging infrastructure. Sending a message to the queue was easy. Checking that it got there – well that’s another story.
My success for criteria for my test for sending a message was to check that the message arrived. And it arrived. Sometimes before the test ended (success) and sometimes after (failure). You see, MSMQ has a mind of its own (also known as asynchronous behavior). I couldn’t control its behavior, so I had to replace it with another object I could control. This was my first mock object.
Mocking is generally an overloaded term (that’s why I like isolation better). But at its base – it’s about changing behavior. Which behavior? Dependency behavior.
Let’s look at my class:
1 |
<span class="kwrd">public</span> <span class="kwrd">class</span> Server<br /><br />{<br /><br /><span class="kwrd"> public</span> <span class="kwrd">void</span> SendMessage(MessageQueue queue, <span class="kwrd">object</span> message)<br /><br /> {<br /><br /> queue.Send(message);<br /><br /> }<br /><br />} |
I need to send the message to the queue. But, like I said, queue (which is the dependency of Server) sometimes behaves funny. And we don’t like funny, we like dependable. Let’s change the signature a bit:
1 |
<span class="kwrd">public</span> <span class="kwrd">class</span> Server<br /><br />{<br /><br /><span class="kwrd"> public</span> <span class="kwrd">void</span> SendMessage(IMessageQueue queue, <span class="kwrd">object</span> message)<br /><br /> {<br /><br /> queue.Send(message);<br /><br /> }<br /><br />} |
This time, I’m not sending a MessageQueue object. Instead, I’m sending the IMessageQueue interface, which looks like this:
1 |
<span class="kwrd">public</span> <span class="kwrd">interface</span> IMessageQueue<br /><br />{<br /><br /><span class="kwrd"> void</span> Send(<span class="kwrd">object</span> message);<br /><br />} |
Now that I can inject any object implementing the IMessageQueue interface. For example, my real Message Queue object looks like this:
1 |
<span class="kwrd">public</span> <span class="kwrd">class</span> RealMessageQueue : IMessageQueue<br /><br />{<br /><br /> var queue = MessageQueue.Create(<span class="str">"AnyQueue"</span>);<br /><br /><span class="kwrd"> public</span> <span class="kwrd">void</span> Send(<span class="kwrd">object</span> message)<br /><br /> {<br /><br /> queue.Send(message);<br /><br /> }<br /><br />} |
But another, a fake message queue object can look like this:
1 |
<span class="kwrd">public</span> <span class="kwrd">class</span> FakeMessageQueue : IMessageQueue<br /><br />{<br /><br /><span class="kwrd"> public</span> <span class="kwrd">bool</span> messageWasSent = <span class="kwrd">false</span>;<br /><br /><span class="kwrd"> public</span> <span class="kwrd">void</span> Send(<span class="kwrd">object</span> message)<br /><br /> {<br /><br /> messageWasSent = <span class="kwrd">true</span>;<br /><br /> }<br /><br />} |
As you can see, with the FakeMessageQueue, I can actually test that the message was sent:
1 |
[TestMethod]<br /><br /><span class="kwrd">public</span> <span class="kwrd">void</span> Send_StringMessage_MessageWasSent()<br /><br />{<br /><br /> var fakeMessageQueue = <span class="kwrd">new</span> FakeMessageQueue();<br /><br /><br /><br /> var server = <span class="kwrd">new</span> Server();<br /><br /> server.SendMessage(fakeMessageQueue, <span class="str">"message"</span>);<br /><br /><br /><br /> Assert.IsTrue(fakeMessageQueue.messageWasSent);<br /><br />} |
And that’s the whole idea behind isolation- the ability to change behavior. Today I wouldn’t advise to go down the manual way – Read here why you should, nay, must use an isolation framework. But sometimes, it’s nice to go down memory lane, see how far we’ve come…