Monday, 27 February 2012

How do you test a project without affecting the database?

Today I sat with a colleague and went through how we could implement testing on existing code, without affecting the data in the database. For anyone who answers that question the words “Dependency Injection” – well done! Maybe this post isn’t for you!
But I wanted to give anyone asking themselves this question a short guide on how to get this working, as it is a common problem faced when adapting an existing project to include unit testing.

The problem is now, you’ve wiped the password for that user. If it is hashed in the database, you have no way of retrieving it without modifying it manually. I suppose you could re-apply the original user, but then you are now having to do a tidy up exercise after every test. If another test depends on that user account being valid (e.g. a UI test to log that user in), then you’re going to fail more tests and the problem will only get worse.

Dependency Injection

Dependency Injection allows us to “inject” the database we would like to modify. Some developers like to have their own database that can be freely modified whenever. But in the long term, the maintenance of tidying this database, coupled with the speed of database connections for thousands of tests becomes unmanageable. Ideally, you want these tests to pass as soon as possible so you can get on with your work.

But as this code stands, we will always point at the database. So we’ll need to do some slight modifications to get this code more flexible, without breaking existing code.

Step 1 – Extract an interface

The easiest step is to use Visual Studio to extract an interface for you. You do this by right clicking on the class name of the DataAccess layer > Refactor > Extract Interface

Once you’ve clicked “Select All” and “OK”, this gives you your current code, implementing a newly created interface, which I will rename IRepository (and make public).

Step 2 - Adapt the service layer to accept an IRepository

Next, we adapt the UserService class to accept a new parameter, to allow us to “inject” the database into the class. This way, existing code still works and the test code can take advantage of the new constructor.

Notice I’m using an internal constructor intentionally, as I don’t want to expose this to just anyone. What I can do is instruct the CLR that internals are visible to another assembly. This is done in the AssemblyInfo.cs class for the DataAccess layer like this:

[assembly: InternalsVisibleTo("Tests")]

Note that I have used the Assembly Name of the assembly to which the internal fields, properties, methods and constructors can be accessed.

Step 3 - Inject the new repository

Now, we are able to modify our test to pass in the TestRepository class we created, so that when the UserService is created, it will access our implementation.

Now – okay – the application will throw an exception! Because we haven’t implemented the TestRepository class and left it at its default implemention, the methods will throw errors. But by writing some simple code, which does as much as we need to get going, we no longer rely on running our tests through the DB:

There are frameworks called Mocking frameworks, that can even alleviate you of this burden. But I’ve yet to explore them enough to include in this blog.

Summary

In this blog, we have looked at a common example that many developers face. We have adapted the existing functionality, without breaking existing code, but extending it for use with a testing framework.

This adaptation allows you to concentrate on testing all of those permutations within the UserService, which is what we actually want to test.

I will adapt a full tutorial of this blog, so that users can try out the refactoring for themselves.