It took me some time, but now it’s raining outside and I have the time necessary to finish the little series about unit tests and it’s related concepts, namely dependency injection and mocking.
Here is the table of contents of the series:
- Experimental unit tests
- Unit tests – it’s just the beginning
- Dependency injection – looking for freedom
- Dependency injection with Unity
- Mocking your dependencies away
We’ve seen what unit tests are and why dependency injection is a usefull method helping you to isolate the unit to test from it’s dependencies. So, everything seems fine and the series could have ended there. Well, in theory, yes. But reality shows that a class to test may have so many dependencies that it may seem to much work to write all the fake classes.
Consider the following example where you want to unit test a person object implementing the IPerson interface:
public interface IPerson
{
string Name { get; set; }
DateTime Birthday { get; set; }
IIdentityCard IdentityCard { get; set; }
Boolean CheckIdentity(int number);
}
//Implementation of IPerson to unit test
public class Person: IPerson
{
private Person(){}
// A person instance can only be created by passing an IIdentity object
public Person(IIdentityCard identity)
{
this.IdentityCard = identity;
}
public string Name { get; set; }
public DateTime Birthday { get; set; }
public IIdentityCard IdentityCard { get; set; }
}
Take a look at the IdentityCard property of type IIdentityCard. A person instance can only be instanciated if you pass an IIdentityCard instance into the constructor. This means, that you must create an IIdentityCard object to unit test the Person class, even if don’t need it because you just want to test the Name-property.
To make things worse, have a look at the IIdentityCard interface:
public interface IIdentityCard
{
int Number { get; set; }
ICertificate Certificate { get; set; }
bool Validate();
}
Note the Certificate-property of type ICertificate. This means, that to unit test your person you may also have to create an object implementing ICertificate, if you need the Certificate-property for your unit test. In that case it may be easier to mock the dependencies instead of writing fake classes.
Mocking means that you have a mocking framework allowing you to create a kind of faked implementation of an interface or base class without having to write a real fake class. This allows you to just implement the members of the mocked class needed for your unit test and to ignore the other members. In this article, I use the moq framework.
Let’s have a look how it works when unit testing the person class shown above (as usual, I use Nunit as unit testing framework):
[TestFixture]
class UnitTests
{
[Test]
public void MoqIPerson()
{
//Create mock of IIdentityCard needed to instanciate a Person
var identity = new Moq.Mock<IIdentityCard>();
//Make the properties of the IIdentityCard mock work like real properties
identity.SetupAllProperties();
//Assign a value to the number property
identity.Object.Number = 1234;
//Create a real person based on a mocked IIdentityCard instance
Person person = new Person(identity.Object);
//Test the Number property of the persons identity
Assert.AreEqual(1234, person.IdentityCard.Number);
}
}
You see that there is no fake class implementing the IIdentityCard-interface. Instead the mock framework does it for you. Even better, with one line of code you can instruct the mocked object to let it’s properties behave like real properties, being able to read and write them.
You can also implement methods of a mocked object by using Lambda expressions. For example, the IIdentity-interface has a validate-method. If we want to make use of it in our unit test, we can configure it using the Setup/Return pair to define the behaviour of the method like this:
identity.Setup(ic => ic.Validate()).Returns(() => identity.Object.Number > 0); Assert.IsTrue(identity.Object.Validate());
Now the Validate-method returns true if the number-property of the IIdentity-mock is greater than zero. Have a look at the moq framework to find more information about how mock objects work and what else you can do with them. Also consult this article explaining very well how to configure the Setup/Return pair of a method to implement.
Now, having an idea about what mocks are, you may ask you-self what is better: defining and using fake classes or writing mocks?
To me, it depends on the degree of dependencies of the class you want to unit test. The more dependencies it has, the easier it is to use mocks instead of writing the necessary fake classes by hand.
On the other side, mocks are always defined and created at run-time, meaning that you can not make use of them in the design-time configuration of your dependency injection framework, where a fake class implementing an interface is interchangeable with every other fake or production class implementing the same interface. This interchangeablility may come handy, because it allows you to switch between unit testing (making use of fake classes) and integration testing (making use of production classes) by referencing different sections of the unit testing configuration section.
I also consider to many dependencies as a code smell, telling me that the class design of the application may be to complex. Remember, that object design and database design are different things. You don’t have to reuse a complex object (like the Person object above) for every use case in the application but instead you can create a light-wight Person object if you just need the person’s name to display it in a combobox. Using light-wight objects naturally reduces the dependency when unit-testing later.
5 May




