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.
public class Person { public string Id; public string FirstName; public string LastName; public Person(string newId, string fn, string ln) { Id = newId; FirstName = fn; LastName = ln; } }
public interface IPersonRepository { List<Person> GetPeople(); Person GetPersonById(string id); }
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.
public class PersonService { private IPersonRepository personRepos; public PersonService(IPersonRepository repos) { personRepos = repos; } public List<Person> GetAllPeople() { return personRepos.GetPeople(); } public List<Person> GetAllPeopleSorted() { List<Person> people = personRepos.GetPeople(); people.Sort(delegate(Person lhp, Person rhp) { return lhp.LastName.CompareTo(rhp.LastName); }); return people; } public Person GetPerson(string id) { try { return personRepos.GetPersonById(id); } catch (ArgumentException) { return null; // no person with that id was found } } }
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.
using System; using System.Collections.Generic; using NUnit.Framework; using NUnit.Mocks; [TestFixture] public class PersonServiceTest { // The dynamic mock proxy that we will use to implement IPersonRepository private DynamicMock personRepositoryMock; // Set up some testing data private Person onePerson = new Person("1", "Wendy", "Whiner"); private Person secondPerson = new Person("2", "Aaron", "Adams"); private List<Person> peopleList; [SetUp] public void TestInit() { peopleList = new List<Person>(); peopleList.Add(onePerson); peopleList.Add(secondPerson); // Construct a Mock Object of the IPersonRepository Interface personRepositoryMock = new DynamicMock(typeof (IPersonRepository)); } [Test] public void TestGetAllPeople() { // Tell that mock object when the "GetPeople" method is // called to return a predefined list of people personRepositoryMock.ExpectAndReturn("GetPeople", peopleList); // Construct a Person service with the Mock IPersonRepository PersonService service = new PersonService( (IPersonRepository) personRepositoryMock.MockInstance); // Call methods and assert tests Assert.AreEqual(2, service.GetAllPeople().Count); } [Test] public void TestGetAllPeopleSorted() { // Tell that mock object when the "GetPeople" method is called to // return a predefined list of people personRepositoryMock.ExpectAndReturn("GetPeople", peopleList); PersonService service = new PersonService( (IPersonRepository) personRepositoryMock.MockInstance); // This method really has "business logic" in it - the sorting of people List<Person> people = service.GetAllPeopleSorted(); Assert.IsNotNull(people); Assert.AreEqual(2, people.Count); // Make sure the first person returned is the correct one Person p = people[0]; Assert.AreEqual("Adams", p.LastName); } [Test] public void TestGetSinglePersonWithValidId() { // Tell that mock object when the "GetPerson" method is called to // return a predefined Person personRepositoryMock.ExpectAndReturn("GetPersonById", onePerson, "1"); PersonService service = new PersonService( (IPersonRepository) personRepositoryMock.MockInstance); Person p = service.GetPerson("1"); Assert.IsNotNull(p); Assert.AreEqual(p.Id, "1"); } [Test] public void TestGetSinglePersonWithInalidId() { // Tell that mock object when the "GetPersonById" is called with a null // value to throw an ArgumentException personRepositoryMock.ExpectAndThrow("GetPersonById", new ArgumentException("Invalid person id."), null); PersonService service = new PersonService( (IPersonRepository) personRepositoryMock.MockInstance); // The only way to get null is if the underlying IPersonRepository // threw an ArgumentException Assert.IsNull(service.GetPerson(null)); } }
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
#1 by hitesh at January 15th, 2008
| Quote
Very good sample…it helps me to understand the creation of mock object and use them for unit testing
#2 by Christopher Piggott at February 28th, 2008
| Quote
I tried the above example using my own classes, but I get this:
at System.Runtime.Remoting.Proxies.RealProxy..ctor(Type classToProxy, IntPtr stub, Object stubData)
at NUnit.Mocks.DynamicMock.get_MockInstance()
at SerialWidgetTest_Test.SSHStreamTest.Test1() in C:\WORK\firmware\Helpers\C#\trunk\TestWidgets\TestWidget_NUnit\SSHStreamTest.cs:line 27
I’m not even sure what that means. Is the type of object I’m trying to mock too complex?
#3 by Geoff Lane at February 28th, 2008
| Quote
Christopher,
Was that an ArgumentException? Using this technique and NMock you can only mock things based on an Interface, not a concrete types. Using an interface is a good practice anyway because it leads to a looser coupling of your objects.
If your really must mock concrete classes (you want to give up loose coupling, or are dealing with dependencies that were not written by you), you might want to look at another Mocking framework like Rhino Mocks.
Hope that helps.
#4 by Chad at May 21st, 2008
| Quote
Hi Geoff
Im wading my way through loose coupling using interfaces. Forcing me to think about my dependencis before I code. What would be a quick example of your classes using asp.net as a GUI using the above example?
Regards
Chad
#5 by Geoff Lane at May 22nd, 2008
| Quote
Chad,
In a Real application the Service would likely implement an Interface as well. You could then call the Service from UI code. Using ASP.NET, you would likely need to use a framework like Spring .NET to wire together your dependencies. If you do that though, you can then inject those dependencies into your Pages.
public class ViewPerson : Page {
private IPersonService personService;
protected void Page_Load(object sender, EventArgs e)
{
Person person = personService.GetPerson(Request.QueryString["personId"]);
// ... do something with person
}
}
That doesn’t necessarily help a lot with Unit Testing though. Web/UI code is hard to unit test. Your best bet is to keep your UIs very thin, with very little code, and use it merely as a translation layer to get things out of the Web context and into “plain code” context. Then you can Unit Test all of the other code and leave testing of UIs to functional tests.
#6 by Dave Paulino at July 1st, 2008
| Quote
@Chad
Very good article and very well explained. This will help developers to understand mock object.
@Geoff
Using the scenario above I agree it is very hard to unit test, but we can use to MVP design pattern to unit test our code.
#7 by Deva at July 2nd, 2008
| Quote
Hi,
Do you have a documentation for the NMock Example Project given
#8 by Kristofer Krause at June 29th, 2009
| Quote
Here is a “concrete” example of the above classes (no Spring). Please let me know what you guys think. Thanks.
http://www.kriskrause.com/2009/06/concrete-example-mocking-net-objects.html