Friday, October 8, 2010

Dependency Injection Part 5: Mocking and Cool Tests

In my last post, we wrote a set of unit tests exercising ConsoleInputService, MessageService, and ConsoleOutputService. We tested these classes thoroughly, and in isolation since their behavior was easier to test in a controlled environment. Its now time to test our main stimulation class Magic8BallSimulator.

Remember our humble Magic8BallSimulator class? If not, here's a quick refresh:This class depends on IMessageService, IInputService, and IOutputService and those dependencies are injected via Magic8BallSimulator's constructor. Since unit testing requires a controlled environment, we'll need to make sure that the instances of IMessageService, IInputService, and IOutputService that we instantiate and inject behave in predictable ways. Remember, unit tests aim to test a simple unit of code, and for our purposes a "unit" is a method within a class.

So we have a problem

We need to make sure that the instances of IMessageService, IInputService, and IOutputService that we instantiate and inject into Magic8BallSimulator behave in predictable ways, but we want those instances to behave in different predictable ways for different tests. Consider this test:

[Test]: We want to make sure Magic8BallSimulator prints an exit message before it exits.

To get our injected instances to behave in the way we need them to for this test, we'll have to do the following:
  • Create a InputServiceStub class implementing IInputService. All the method-bodies in in this class will be empty except for ExitWasRequested() which will always return true
  • Create a OutputServiceStub class implementing IOutputService. All the method-bodies in this class will also be empty empty expect for PrintExit() which will set a public PrintExitCalled property to true when called.
  • Create a MessageServiceStub class implementing IMessageService with empty methods.
  • Instantiate the 3 classes above. Instantiate Magic8BallSimulator and inject our 3 test instances
  • call Magic8BallSimulator.Run(), and then make sure that OutputServiceStub.PrintExitCalled is true.
No Thanks!

That's too much code for us to write and maintain to test 1 case. We still have to test Magic8BallSimulator, however, after-all they pay us to write software :) The problem is, we don't want to have to write three classes to test 1 case. One way out might be to create 3 abstract classes implementing IMessageService, IInputService, and IOutputService and then extend those class only filling in the method-bodies we need for our test. That still turns out to be a ton of code to maintain, and we'd like our application to be fun to work on, not a pain in the ass. Here's a better way.

I love Moq. Check this out

We can leverage the badass, open-source, Moq library to create mock implementations of IMessageService, IInputService, and IOutputService and then use lambda expressions to stand in for the methods we want. We can then inject those mock classes into Magic8BallSimulator. Feel the lightness of the test below :)Hey, make sure you read the comments above, that's where the good explanations are! Now that we're able to use Moq to mock our dependencies, additional tests are easy! Here are 3 more:
That's it. It's been fun!

Here's the source code for this post. Thanks so much for reading these posts on Dependency Injection and Unit Testing. I had lots of fun writing these and only hope my silly examples and code-snippets were clear. If you have any questions, go ahead and leave a comment and I'll try to help you out.

1 comments:

Anonymous said...

Awesome post, thanks so much for sharing your knowledge using easy to learn examples.