Unit Testing Legacy Code with Dependency Injection and Mock Objects – Part III
Unit Testing Legacy Code with Dependency Injection and Mock Objects – Part III
In the last post, we got to the point where we can do dependency injection of the web service object. Now we’ll actually do some injection, using mock objects for unit tests. For this demonstration, I’ll be using NUnit for the unit test framework. This would work just as well (with minor syntax changes) for Microsoft’s unit testing framework. I’ll also be manually creating the mock objects that will be used for the tests. There are some libraries out there that will give you a whole framework for mocking classes, but I think that using the manually created classes (and seeing their source code) will be a bit clearer. If you’re interested in the mocking libraries, check out NMock, RhinoMock, and TypeMock.
The first thing to do is install the tools we need for unit testing. NUnit is what I generally use. I also use TestDriven.Net to help with testing. It lets you run your tests while still inside Visual Studio.
Now, we can open up the solution in Visual Studio and create a new ‘class library’ project (TestBusinessObjects) to hold our unit tests. That project needs to have a reference to the BusinessObjects project and another one to ‘nunit.framework’ (which is available under the .Net tab when you add a reference to a project, as long as you’ve installed NUnit). Then we can create our first test class, which I’ll name TestPropertyAddress.cs. The code for the class is listed below.
TestPropertyAddress.cs
using BusinessObjects;
using NUnit.Framework;
[TestFixture]
public class TestPropertyAddress
{
[Test]
public void SavePropertyAddress_ShouldSucceed()
{
PropertyAddress propAddr = new PropertyAddress();
propAddr.Save( “1234 Main Street”, “Houston”, “TX”, “77777″ );
}
}
The “[TestFixture]” before the class, and the “[Test]” before the SavePropertyAddress_ShouldSucceed() method, designate that these are used for unit testing. Within our test method, we create a PropertyAddress object and attempt to save some data that should be valid. Since Save() has no return value, the test passes as long as no exception is thrown. If we want to test a method that returns a value, NUnit has methods you can call from Assert (see the NUnit documentation for details).
Now, it’s time to create the mock object. I’ll create a MockPropertyAddress class in the TestBusinessObjects project and have it implement the IAddressValidator interface. I’ll also add in a way to let me determine how the mock object should respond when executed. The code for this class is below.
MockAddressValidator.cs
public class MockAddressValidator : BusinessObjects.IAddressValidator
{
public enum Responses
{
ReturnTrue,
ReturnFalse,
SimulateRealValidation,
ThrowWebException
}
public Responses Response = Responses.SimulateRealValidation;
public bool IsAddressValid( string streetAddress, string city, string stateCode, string zipCode )
{
switch ( Response )
{
case Responses.ReturnFalse :
return false;
case Responses.ReturnTrue :
return true;
case Responses.SimulateRealValidation :
return ( streetAddress != “” && city != “” && stateCode != “” && zipCode != “” );
case Responses.ThrowWebException :
throw new System.Net.WebException();
default:
throw new ArgumentException( “Response was not set to a valid value” );
}
}
}
With this mock class, we can now force our AddressValidator service behave the way we want. We also don’t need to use the real validation service for our tests. Here is the TestAddressProperty.cs class after adding tests for more conditions:
using BusinessObjects;
using NUnit.Framework;
[TestFixture]
public class TestPropertyAddress
{
[Test]
public void SavePropertyAddress_ShouldSucceed()
{
MockAddressValidator validator = new MockAddressValidator();
validator.Response = MockAddressValidator.Responses.SimulateRealValidation;
PropertyAddress propAddr = new PropertyAddress( validator );
propAddr.Save( “1234 Main Street”, “Houston”, “TX”, “77777″ );
}
[Test, ExpectedException( typeof( ArgumentException ), ExpectedMessage = “Property address is not valid. Data was not saved.” )]
public void SavePropertyAddress_MissingData_ShouldFail()
{
MockAddressValidator validator = new MockAddressValidator();
validator.Response = MockAddressValidator.Responses.SimulateRealValidation;
PropertyAddress propAddr = new PropertyAddress( validator );
propAddr.Save( “1234 Main Street”, “Houston”, “”, “77777″ );
}
[Test, ExpectedException( typeof( System.Net.WebException ) )]
public void SavePropertyAddress_ValidatorHasWebException_ShouldFail()
{
MockAddressValidator validator = new MockAddressValidator();
validator.Response = MockAddressValidator.Responses.ThrowWebException;
PropertyAddress propAddr = new PropertyAddress( validator );
propAddr.Save( “1234 Main Street”, “Houston”, “TX”, “77777″ );
}
}
When we create the MockAddressValidator class, we have all the properties and methods of the class visible. That lets us use the Response value to set how we want the object to respond when the other code calls it. Since it implements the IAddressValidator interface, we can pass it in through the constructor of the PropertyAddress class. Then, when PropertyAddress.Save() calls the validation web service, it actually calls our mock one, which gives the response we need for tour tests.
So, there is a way to take some legacy code with dependencies and gradually change it to code that can easily be tested. If you have any questions, please leave a comment.

