Design for testing

This article was originally published in VSJ, which is now part of Developer Fusion.

Developers generally agree that unit testing is a good idea, however not all of us know how to go about authoring code that is testable. The solution proposed in this article involves deliberately inserting a mechanism for testing at the point that you write the code. For example, if I need to access a database I typically create some kind of data access layer. That layer provides a facade over the database, I create instances of objects from that layer to perform the database access. If I want to test the data access code I need to be able to stub in the database. If I need to test the code that uses the data access code I need to be able to stub in the data access layer. This article will talk about the various approaches we have to writing code that is testable looking at factories, dependency inject and “inversion of control”.

Layer code

The first rule of design for test is really very straightforward. Write your code in layers. Taking the above example; instead of sprinkling your data access code throughout your business logic, separate the data access code into layers. You often see data access code written as two layers, a low level data access layer and a higher level ‘entity’ layer. The lower level layer provides an API that actually talks to the database, maybe through stored procedures, or through parameterized statements and maybe today through a LINQ layer such as LINQ to SQL. The entity layer exists at a higher level and provides methods such as GetAllCustomers, UpdateCustomer or GetInvoicesFor Customer. This layer calls the lower level methods in the data access layer. Depending on the complexity of the application you may not need to separate the code into this many layers, but layering is always a good idea.

Breaking the code into the layers suggested above you will make testing easier as each layer can be tested separately. As the entity layer is independent of the database then no database is needed to test it, all that need be test (and all that should be tested) is the logic within the layer. Another aspect of layering is that no domain specific code should leak into the business code. For example if you are coding a web application the business logic should be in classes that are entirely separate from the UI code. No UI code should be used in the business logic layer. This is easy to achieve in practice, however it is all too easy to see code like this:

ActionView GetUsers(int id) {
    User.GetUsers(HttpContext.Current);
    ...
}

In this case there is a GetUsers business method, but this is being passed an HttpContext which is an ASP.NETet type. This means that the User type depends on the ASP.NETet assemblies and also that to test the User type you will need to create a dummy HttpContext, which is a non-trivial task that you shouldn’t need to do. Writing the method like this:

ActionView GetUsers(int id) {
    string startsWith = Request.Params
    	["startsWith"] as string
    		User.GetUsers(startsWith);
    ...
}

…means that the GetUser method takes a string. This is much better layering and makes the code much easier to test.

Use of ‘new’ considered evil!

One of the cardinal rules of software development is ‘code to abstractions and not to concrete types’, and it cannot be emphasised strongly enough how important this is. By coding to concrete types you are limiting yourself to specific implementations within your application. While at first glance this seems reasonable it means that you cannot substitute those types for doubles when you want to test the code. If the concrete types touch a database, the file system or maybe a web service then this makes testing much harder than it should be. By coding to abstract types and also abstracting away object creation you allow doubles to be substituted in much more easily.

For example, code like this:

public IEnumerable<Users> GetUsers() {
    UserDAO dao = new UserDAO();
    return dao.GetUsers();
}

…is inherently non- testable, or at least is very difficult to test. This is because the code is using a concrete type UserDAO. This DAO will call some other type which will access a database. This means that either the types used by the UserDAO must be dummied up or the database access must be faked, maybe by using a test database. Instead of this the code should be written against a UsersDAO abstraction, either an interface type or an abstract class. The code would then look like:

public IEnumerable<Users> GetUsers() {
// IUserDAO idao = GetUserDAOSomehow();
    return idao.GetUsers();
}

Of course this leaves us with the problem of getting hold of a UsersDAO instance and the rest of this article will discuss those options.

Dependency injection

Dependency injection is a phrase that has come into use over the last few years. It’s an important sounding phrase for a straightforward concept. The basic idea is simple, rather than a type or method, create the objects it relies on, i.e. those objects that are passed into the object or method. Why dependency injection? Well objects depend on other objects, and thus dependent objects are passed into, or injected into the depending objects.

Dependencies can be injected in three ways: parameter injection, setter injection or constructor injection. To examine these uses we will write examples around a ManageAuthors class. This class looks like this:

public class ManageAuthors
{
    public Author GetAuthor(int id)
    {
    	AuthorDAO authorDao =
    		new AuthorDAO();
    	return
    		authorDao.GetAuthorWithId(id);
    }
}

This uses an AuthorDAO class that looks like this:

public class AuthorDAO
{
    public Author GetAuthorWithId(
    	int au_id)
    {
    	return new Author()
    	{FirstName = "Kevin",
    		Surname = "Jones" };
    }
}

As mentioned above the code is difficult to test. The DAO is hard (impossible) to replace. To make this code testable we need to code to an abstraction rather than a concrete type (the AuthorDAO). There are several steps that need to be completed to do this.

The first thing to do is to create an abstract type that the ManageAuthors class can use instead of the AuthorDAO. The AuthorDAO needs to derive from this abstraction. We then end up with classes something like this:

public interface IAuthorDAO
{
    Author GetAuthorWithId(int au_id);
}

public class AuthorDAO : IAuthorDAO
{
    public Author GetAuthorWithId(
    	int au_id)
    {
    	return new Author()
    	{ FirstName = "Kevin",
    		Surname = "Jones" };
    }
}

Now that we have the interface (the abstraction) in place we can code against it. The simplest way to do this is to use parameter injection. This involves changing the signature of the method to accept a parameter of the correct type:

public Author GetAuthor(
    IAuthorDAO authorDao, int id)
{
    return authorDao.GetAuthorWithId(id);
}

Notice that now the IAuthorDAO is being passed to the method. This makes the method easily testable:

[Test]
public void TestValidAuthor()
{
    ManageAuthors sut =
    	new ManageAuthors();
    IAuthorDAO idao = new MockAuthorDAO();
    Author a = sut.GetAuthor(idao, 1);
}

Where the MockAuthorDAO class looks like this:

public class MockAuthorDAO : IAuthorDAO
{
    #region IAuthorDAO Members
    public Author GetAuthorWithId(
    	int au_id)
    {
    	return new Author()
    		{ FirstName = "Foo",
    			Surname = "Bar" };
    }
    #endregion
}

Notice that the method now doesn’t create the object it depends on, instead the object is injected via the parameter passed to the method.

One problem with this mechanism is that existing code has to change, in fact it’s worse than that as existing method signatures have to change, this could mean a lot of code changes in a large code base.

To mitigate this we could use ‘setter injection’. Now, rather than inject the dependencies via a parameter the class is re-written to have a property that is set by external code. This property is of the abstract type, IAuthorDAO in the above code. The ManageAuthors class now changes to look like this:

public class ManageAuthors
{
    public IAuthorDAO AuthorDAO
    	{ get; set; }

    public Author GetAuthor(int id)
    {
    	return
    		AuthorDAO.GetAuthorWithId(id);
    }
}

This is better as less code has to change. However there is still a danger here. While the ManageAuthors class doesn’t need to change as much, all the code calling it does need to change. The danger now is that all the places where the calling code uses the GetAuthor method have to remember to inject the IAuthorDAO, and this may be missed.

The third option is to use constructor injection. In this case the ManageAuthors class would be changed to have a constructor that takes an IAuthorDAO as a parameter. The code would then look like:

public class ManageAuthors
{
//readonly IAuthorDAO authorDAO;
    public IAuthorDAO authorDAO
    	{ get; set; }

    public ManageAuthors(
    	IAuthorDAO authorDAO)
    {
    	if (authorDAO == null)
    		throw new ArgumentNullException(
    			"authorDAO");
    	this.authorDAO = authorDAO;
    }
}

Calling this code then involves passing an IAuthorDAO to the ManageAuthors constructor:

[Test]
public void
    TestValidAuthorWithConstructor()
{
    ManageAuthors sut = new ManageAuthors(
    	new MockAuthorDAO());
    Author a = sut.GetAuthor(1);
    Assert.AreEqual("Foo", a.FirstName);
    Assert.AreEqual("Bar", a.Surname);
}

This has the benefit that it signals to all the calling code exactly how the class should be used, i.e. an IAuthorDAO must be passed to the constructor. Any code compiled against the ManageAuthors class would fail to compile; this is a strong signal that the code is wrong! However, if the ManageAuthors code is used by a lot of other assemblies then re-coding the classes in those assemblies may be a long and tedious process.

Another cardinal rule of software development is ‘don’t change working code’, in this case a lot of working code would have to be touched. To mitigate this, the ManageAuthors class could be changed to have a default constructor that called the new constructor. The class would look something like:

public class ManageAuthors
{
    readonly IAuthorDAO authorDAO;
    public ManageAuthors():this(
    	new AuthorDAO()){}

    public ManageAuthors(
    	IAuthorDAO authorDAO)
    {
    	if (authorDAO == null)
    		throw new ArgumentNullException(
    			"authorDAO");
    	this.authorDAO = authorDAO;
    }
}

Care needs to be taken with this approach to ensure that the correct class is instantiated in the default constructor and that new code does not use the default constructor. A better approach may be to have the default constructor create a ‘faulting’ IAuthorDAO, one that logs the fact that it shouldn’t be called and then throws an exception. This means that as the ManageAuthors class is distributed more widely, code using it can be updated more easily.

Of the three approaches to dependency injection, parameter, setter and constructor, constructor is the most widely used. It is generally easier to retro-fit to existing classes and also makes it relatively easy to get existing code to work with the changed ManageAuthors class if the default constructor is kept in place.

Factories

Suppose you find for whatever reason that you cannot or simply do not want to use dependency injection, how do you go about creating objects without the use of the new keyword? One option is to use a factory. The Gang of Four patterns book lists two factory patterns, the factory method and the abstract factory. An abstract factory is simply a collection of factory methods, so understanding factory method leads you to an understanding of abstract factory.

In the factory method pattern the idea is to define a type that is able to create the type you want to use. For the AuthorDAO type above we’d create an AuthorDAOFactory. Factories can also be substituted. So, like any other types, when defining a factory it makes senses to define a base abstract factory and then define concrete instances of that abstraction that our code actually uses. The code for using the factory will look like this:

public Author GetAuthorWithFactory(
    int id)
{
    AuthorsDAOFactory factory =
    	LoadFactory();
    AuthorsDao = factory.GetAuthorsDAO();
    return AuthorsDao.GetAuthor(id);
}

Here we load the factory (we will see how to do this in a moment), then uses the factory to create the AuthorsDAO object which we can finally call.

The factory code looks like this, first the abstract class:

public abstract class AuthorsDAOFactory
{
    public abstract AuthorsDAO
    	GetAuthorsDAO();
}

…then the concrete implementation:

public class SimpleAuthorsDAOFactory :
    	AuthorsDAOFactory
{
    public override AuthorsDAO
    	GetAuthorsDAO()
    {
    	return new SimpleAuthorsDAO();
    }
}

The factory method pattern gets its name from the fact that there is one method in the class whose job it is to create the object we care about. Notice that this code uses ‘new’. This makes sense – ‘new’ has to be used somewhere, our job is to abstract away where ‘new’ is used.

Notice that the ManageAuthors class uses the abstract AuthorsDAOFactory type which returns an abstract AuthorsDAO type. This means that all our code relies on abstractions, making testing much easier. A test for this method would look like this:

[Test]
public void TestWithFactory()
{
    ManageAuthors manageAuthors =
    	new ManageAuthors();
    Author author = manageAuthors.
    		GetAuthorWithFactory(1);
    Assert.AreEqual("Alice", author.Name);
}

Notice that there is no mention of a factory here. The factory is set up purely using configuration. The main application’s configuration file (with the real factory in) would look like:

<appSettings>
    <add key="factory" value=
    "DAOFactory.SimpleAuthorsDAOFactory,
    		DAOFactory"/>
</appSettings>

…while the test configuration file looks like this:

<appSettings>
    <add key="factory" value=
"TestAuthorManager.MockAuthorDAOFactory,
    	TestAuthorManager"/>
</appSettings>

So changing the configuration changes the factory being loaded. This helps solve the mystery of how the ManageAuthors class loads the factory. The LoadFactory method gets the factory type name and assembly from the config file, then uses reflection to load the assembly and create an instance of the factory:

private static AuthorsDAOFactory
    LoadFactory()
{
    string typeAsString =
    	ConfigurationManager.
    	AppSettings["factory"];
    Type type =
    	Type.GetType(typeAsString);
    AuthorsDAOFactory factory =
    	(AuthorsDAOFactory)Activator.
    		CreateInstance(type);
    return factory;
}

The configuration file stores the factory as a fully qualified type name which can then be loaded using Type.GetType. This means that not only is testing easier but anytime we want to change the factory it is simply a configuration update.

However, this is still an issue. For example, if you want to test multiple factories then the configuration needs to be changed every time, meaning multiple app.config files in multiple test projects. Sometimes it would be nice to have a configuration option that can be overridden in code. This is where containers and inversion of control come into play.

Inversion of control

A container is an object where an application can store references to other objects and retrieve them later. The references can be stored by having the container read a configuration file and creating the objects, just as we saw for the factory. Or the application can create objects in code and store those references in the container. This is known as inversion of control because the control of creating the dependent object is taken away from the code using that object.

There are various containers available. In these examples we’ll use the Unity container provided by Microsoft as part of the Enterprise Library. This container can be configured in the application’s configuration file:

<configuration>
    <configSections>
    	<section name="unity"
    		type="Microsoft.Practices.Unity.
    Configuration.UnityConfigurationSection,
Microsoft.Practices.Unity.Configuration"
    	/>
    </configSections>
    <unity>
    	<typeAliases>
    		<typeAlias alias="AuthorsDAO"
    			type="DAO.AuthorsDAO, DAO" />
    		<typeAlias
    			alias="SimpleAuthorsDAO"
    	type="DAO.SimpleAuthorsDAO, DAO" />
    	</typeAliases>

    	<containers>
    		<container>
    			<types>
    				<type type="AuthorsDAO"
    					mapTo="SimpleAuthorsDAO" />
    			</types>
    		</container>
    	</containers>
    </unity>
</configuration>

The first part of the file sets up the Unity configuration section handler. The unity section then configures the container. The unity section defines two aliases, these are there so we can refer to the types through the alias within the configuration file, rather than having to use fully qualified type names everywhere. We then set up aliases for the AuthorsDAO abstract type and the SimpleAuthorsDAO concrete type. Finally in the containers section we create a mapping between these two types. This mapping basically says, ‘when code asks for something of type AuthorsDAO give them a SimpleAuthorsDAO object’.

The configuration for the container must be loaded and parsed. Once that is done an application can then load objects from the container. To do this, provide a simple wrapper class:

public class Container
{
    private static Container container;

// load configuration data here
    private Container()
    {
    	...
    }
    readonly IUnityContainer
    	unityContainer =
    		new UnityContainer();

    public static Container Instance
    {
    	...
    }

    public T Resolve<T>()
    {
    	return unityContainer.Resolve<T>();
    }

    public void RegisterType<TFrom, TTo>()
    	where TTo : TFrom
    {
    	unityContainer.RegisterType<
    		TFrom, TTo>();
    }
}

Note that the Resolve method is generic. The container will look up the type passed through the generic parameter and return its mapped type. This is used something like this:

public Author GetAuthorWithIoC(int id)
{
    AuthorsDao = Container.Instance.
    	Resolve<AuthorsDAO>();
    return AuthorsDao.GetAuthor(id);
}

…i.e. ask for an AuthorsDAO object and (hopefully) get return a SimpleAuthorsDAO object. Again this lets us test quite easily. Like for the factory, we create an app.config file to configure the container. But we can now also programmatically inject objects into the container. So in the test code we can do this:

[Test]
public void TestWithIoC()
{
    ManageAuthors manageAuthors =
    	new ManageAuthors();

    Container.Instance.RegisterType
    	<AuthorsDAO, MockAuthorsDAO>();

    Author author = manageAuthors.
    	GetAuthorWithIoC(1);

    Assert.AreEqual("Alice", author.Name);
}

Notice that we are registering a new MockAuthorsDAO with the container before calling the method under test. This will override the instance already in the container and the method under test will resolve AuthorsDAO to MockAuthorsDAO.

This use of containers is very nice. It gives the flexibility of configuration alongside the ability to override that configuration in code which makes managing testing in particular very straightforward.

Types of Test Doubles

In the above code we have written a very simple MockAuthorsDAO class to use for testing. This gets us into the murky world of ‘Test Doubles’. On his ‘bliki’ (www.martinfowler.com/bliki/TestDouble.html) Martin Fowler categorises the various test doubles. He makes a distinction between Dummies, Fakes, Stubs, Spies and Mocks. According to his definitions the ‘mock’ above is probably a Stub. Mocks are more full featured and typically are coded with ‘expections’. Something along the lines of ‘If I call this method passing the value 1, return ‘foo’, if I pass the value 2, return ‘bar’ and so on. Mocks can be built by hand but it is often easier to use a framework designed specifically to create them.

There are several mocking frameworks available and more are becoming available all the time. The most popular is probably Rhino Mocks but there are others such as Moq or NMock.You are recommended to try them and choose the one you prefer.

Conclusion

To make your code more testable you should follow a couple of simple rules. Firstly, write in layers. This makes each layer more testable. Secondly, code to abstractions. If you code to an abstraction you move away from calling ‘new’. This means that you can then get references to objects in other ways. Do this either through dependency injection, factories or containers. Using any of these mechanisms means that these references become pluggable and therefore more testable.

You might also like...

Comments

About the author

Kevin Jones United Kingdom

Kevin Jones has been involved in software development and design for more years than he cares to remember, and has been involved in training and consultancy since 1990. He is the co-author of Se...

Interested in writing for us? Find out more.

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.” - Donald Knuth