NUnit is my Unit Testing tool of choice for .NET development. Microsoft provides a unit testing framework but it only works with some higher-end versions of Visual Studio. They're so similar that it's almost ridiculous that Microsoft created their own version. (See one of my previous posts for more information on Automating NUnit with MSBuild.) In the Java world it's fairly common to do Mocking to help make unit testing easier. I've written about using JMock for Unit Tesing in Java. In this post, I'd like to talk about a relatively new feature of NUnit which now supports Mocks out of the box.
What Are Mock Objects
Mock Objects are a technique that allow you to isolate classes from their dependencies for testing purposes. This isolation allows for fine-grained testing of single methods in a single class, possibly even before the dependent classes are fully implemented. This isolation allows your tests to run quickly and it makes testing small pieces of functionality much easier. When you've tested individual pieces of code in isolation you can have much higher confidence in larger-grained tests. This isolation becomes even more interesting when you are dealing with dependencies such as a data layer or a web service layer. External calls like that can be very time consuming or could fail if the remote system is down for maintenance.
One of the great things about using Mock Objects is that they force you to think about the dependencies that your classes and methods have. It forces you to think about the coupling between your classes. If you have high coupling then your code is often harder to test. If you have a loosely coupled design then testing and using Mock Objects is very much easier. Thinking about those design notions early can help you more easily manage change over time.
Maxims:
- Good design is better than bad design
- Loosely coupled objects are usually a better design than tightly coupled objects
- Testing improves code quality and developer efficiency over time
- Testing is easier with a loosely coupled designs
A Sample Project
We're going to start with some simple code. We create a Domain object called Person and an interface for a Data Access object called IPersonRepository. Pretty simple at this point.
Next we create a PersonService object. This would represent all of the business logic in our application. It would interact with the Data Access tier and return information to the UI layer for display.
We wire together our objects using Constructor based Dependency Injection. All of the dependent Objects are sent in through the constructor. This allows for the loose coupling since the PersonService doesn't know about the Implementing class, but only the interface. Since it's done in the constructor we can also never have an invalid PersonService as would be the case if there was a setter for the IPersonRepository implementation.
This is again a fairly straightforward implementation, but I hope enough to display the issue at hand.
Using Mocks with NUnit
Now we can start testing our PersonService. Notice that we haven't even implemented the IPersonRepository yet. That way we can make sure that everything in our PersonService class works as expected without having to think about other layers of the application.
The PersonService doesn't have a lot of logic in it, but I hope this illustrates how you easily can test various conditions using Mock objects. It also illustrates the idea of testing early by allowing you to test some code before all of the dependent objects are implemented.
While the Mocks built into NUnit might not be the most powerful or complete Mocking library out there, it should be sufficient for most uses. I'm sure they will continue to improve them over time as well, so I look forward to them becoming more powerful (and having better documentation) in the future.
Download Code Example: NMock C# Example Project
For more on NUnit you might like to check out:
- Pragmatic Unit Testing in C# with Nunit (Pragmatic Programmers)
- NUnit Pocket Reference (Pocket Reference (O'Reilly))
[ad name="image-banner"]