On numerous projects that I have worked on, the question has always arisen on how to tackle the issue of writing unit tests for existing components that have “been around the block a few times”. Invariably the answer was to only write unit tests for the new functionality and leave what has existed “for eons” well alone – I mean, it works doesn’t it? That may be the case, however it is not long before there are changes required in one area that could well impact on “old faithful”. The other reality, in my experience, the people who originally developed the “solid” code have long since left and now the development team is “aware” of what the code does, but few will dare change it for risk of breaking it. I’ve seen some serious scaffolding go on around existing code for fear of breaking the underlying functionality.
The answer is simple and, when seen from a pragmatic point of view, quite necessary – write the unit tests for that code. It will not only be an education for the developer writing the unit test to really understand the code that is being tested, but could also lead to improving the coupling by way of using Dependency Injection.
The example I have dreamt up here is by no means problematic (nor is it a work of art), the intention is to illustrate some of the methods of actually decoupling the code and using Dependency Injection.
Before going any further we need to mention the two types of Dependency Injection that most people are familiar with: Constructor Injection and Setter Injection.
Constructor Injection
As the name implies, is where the dependency is injected via the constructor. Typically an interface is passed in to the constructor as a parameter and is used to set a member variable:
-
public CustomerManager(ICustomerRepository i_customerRepository)
-
{
-
m_customerRepository = i_customerRepository;
-
}
As you can see the internal member variable is being set to an instance of an object that implements the appropriate interface. As for the introduction of a null, there are several approaches on this:
- Detect the null and instantiate a related “Null” type (not a null, but a minimal class that implements the expected interface).
- Detect the null and instantiate a known, default type.
- Detect the null and throw an exception.
In the first two cases we would not, strictly speaking, be able to write unit tests for as they would run the risk of changing the test into an integration test – imagine that the known default type was actually the next layer that communicated directly with the DB, you will inadvertently employ the test method that we are trying so hard to avoid. The third case would be testable, but could work out to be impractical in production code – there are instances where it is better to instantiate a default instance and therefore minimize the effect on production code. With this in mind, let’s return to the example previously:
-
public CustomerManager()
-
{
-
Initialize(null);
-
}
-
-
public CustomerManager(ICustomerRepository i_customerRepository)
-
{
-
Initialize(i_customerRepository);
-
}
-
-
private ICustomerRepository m_customerRepository;
-
-
private void Initialize(ICustomerRepository i_customerRepository)
-
{
-
m_customerRepository = i_customerRepository ??
-
new BlogSamples.
SqlRepository.
CustomerRepository();
-
}
Setter Injection
Another way of injecting dependency would be to inject via the set method of a property on the object.
Using the example above, consider setting the ICustomerRepository instance via a property instead of the constructor:
-
private ICustomerRepository m_customerRepository;
-
-
public ICustomerRepository Repository
-
{
-
get
-
{
-
if (m_customerRepository == null)
-
{
-
m_customerRepository =
-
new BlogSamples.
SqlRepository.
CustomerRepository();
-
}
-
return m_customerRepository;
-
}
-
set
-
{
-
m_customerRepository = value ??
-
new BlogSamples.
SqlRepository.
CustomerRepository();
-
}
-
}
In this example I have taken a similar stance to what was mentioned previously in the constructor injection scenario. I have treated a null instance with a default instantiation. In this case I do have my doubts as to whether it is the right approach. As soon as we start to introduce default behavior we are immediately “roping off” an area that cannot be touched by proper unit testing (i.e. the idea of isolating the class entirely from it’s resources and injection those dependencies from outside). My only argument in this method’s defense is the fact that if it was true legacy code, I would need to be very careful of the client’s that use the class I am working with – far worse than not testing an a smaller part of the code would be to break existing functionality, from the client code point of view.
In either scenario (Constructor Injection or Setter Injection) we are forcing the decoupling to occur via passing in the dependency from outside the object instance.
The best method of deciding what needs to be injected is to look at what would be implied when creating an instance of a class or calling a static method from within the class in question. If the call to the method or instantiation of a type returns a simple type that did not require any complex business logic or external resources (such as a Database or config file) then chances are you are pretty safe. If, however, an external resource was accessed, then it is an ideal candidate for dependency injection and either method described previously could be used.
Example code
The example that I have prepared involves two classes, CustomerManager and EmployeeManager. Each one accesses the Database instance of the NorthWind DB (on a SQL Server instance) and each one expose typical CRUD methods. The attached zip file contain the before and after of the changes that were made to the code in order to achieve a more de-coupled class and introduce dependency injection (Base – original code; UsingDi – employing dependency injection).
The first phase was to extract the signatures of the appropriate methods and put them in to an interface (ICustomerRepository and IEmployeeRepository).
-
public interface ICustomerRepository
-
{
-
string ConnectionString { get; set; }
-
-
void Insert(Customer i_customer);
-
-
void Load(int i_customerId, out Customer o_customer);
-
-
void Update(Customer i_customer);
-
-
void Delete(Customer i_customer);
-
-
List LoadAllCustomers();
-
}
Once this was done, I then set about refactoring the code that accessed the DB into it’s own assembly and class; implementing the new interface. This then meant that the original CustomerManager class method’s were reduced to essentially to everything except the database access code (in this case it turned out to be a straight call through, however you get the general idea of what the aim of the exercise was):
Before:
-
public void Insert(Customer i_customer)
-
{
-
using (System.Data.
SqlClient.
SqlConnection connection
= new SqlConnection
(this.
ConnectionString))
-
{
-
using (System.Data.
SqlClient.
SqlCommand cmd
= new System.Data.
SqlClient.
SqlCommand())
-
{
-
cmd.Connection = connection;
-
cmd.CommandText =
-
"INSERT INTO Customers (CustomerID, CompanyName, ContactName, ContactTitle, " +
-
"Address, City, Region, PostalCode, Country, Phone, Fax) VALUES " +
-
"(@CustomerID_PARAMS, @CompanyName_PARAMS, @ContactName_PARAMS, " +
-
"@ContactTitle_PARAMS, @Address_PARAMS, @City_PARAMS, @Region_PARAMS, " +
-
"@PostalCode_PARAMS, @Country_PARAMS, @Phone_PARAMS, @Fax_PARAMS)";
-
cmd.Parameters.AddWithValue("@CustomerID_PARAM", i_customer.CustomerID);
-
cmd.Parameters.AddWithValue("@CompanyName_PARAM", i_customer.CompanyName);
-
cmd.Parameters.AddWithValue("@ContactName_PARAM", i_customer.ContactName);
-
cmd.Parameters.AddWithValue("@ContactTitle_PARAM", i_customer.ContactTitle);
-
cmd.Parameters.AddWithValue("@Address_PARAM", i_customer.Address);
-
cmd.Parameters.AddWithValue("@City_PARAM", i_customer.City);
-
cmd.Parameters.AddWithValue("@Region_PARAM", i_customer.Region);
-
cmd.Parameters.AddWithValue("@PostalCode_PARAM", i_customer.PostalCode);
-
cmd.Parameters.AddWithValue("@Country_PARAM", i_customer.Country);
-
cmd.Parameters.AddWithValue("@Phone_PARAM", i_customer.Phone);
-
cmd.Parameters.AddWithValue("@Fax_PARAM", i_customer.Fax);
-
-
connection.Open();
-
-
cmd.ExecuteNonQuery();
-
-
if (connection.State == ConnectionState.Open)
-
{
-
connection.Close();
-
}
-
}
-
}
-
}
After:
-
public void Insert(Customer i_customer)
-
{
-
m_customerRepository.Insert(i_customer);
-
}
Although the example does not show any advantage in factoring out the code to a separate assembly (effectively the class has become so lightweight that it is simply calling through to the dependant instance), it does serve to show how the resource intensive code (i.e. the code that accesses the Database) can be removed to leave the code that can be tested in isolation without the need for accessing the underlying resources.
A small note on refactoring.
I use JetBrains ReSharper in Visual Studio 2008 and since the first day I have had it installed, it has been a real godsend to my code. Apart from all of the syntax highlighting and helpful hints on problematic code, one of the best features is the refactoring. Whilst preparing the code for this blog entry I had to pull out the methods from the original Connector class into an interface. At first I was “horrified” at the prospect of cutting, pasting and pruning the code as I was unsure what I would have been left out or added.
Step in ReSharper. By right clicking on the Method name I get access to the following context menu:

ReSharper Context Menu
When I select extract interfaces I get the following dialog, notice how you can even state where the code for the interface gets pulled out to:

ReSharper Extract Interface Dialog
In the next blog entry I will illustrate how we can use mocking to illustrate how we would go about doing the unit testing.