Tuesday, January 3, 2012

What is dependency injection

Published: 13 Nov 2009
By: Andrew Siemer
In this article we will address the lack of testability that our current application has. We will do this by making our application conform to the dependency injection pattern. This will allow us to push up all of our dependencies which makes our code considerably more testable than it currently is.




Introduction

In the last article we removed the dependency that our front end and middle tier code had on our data access layer. This provided us with an application that has no ties to the data access technology that is used to connect to the surrounding infrastructure. This made the application more flexible in that the data access code and repositories can be swapped out for something new. The codebase however is no more testable than it has been in all of its previous states.
In this article we will address the lack of testability that our current application has. We will do this by making our application conform to the dependency injection pattern. This will allow us to push up all of our dependencies which makes our code considerably more testable than it currently is.

What is dependency injection?

Dependency Injection as defined by Wikipedia is "the process of supplying an external dependency to a software component. It is a specific form of inversion of control where the concern being inverted is the process of obtaining the needed dependency."
The statement above doesn't clearly describe what this means if your head is not already thinking in this realm. For that reason seeing some code that does not use dependency injection vs. seeing some code that does use this pattern tends to make things much easier to comprehend.

Code that doesn't use dependency injection

Let's take a look at a quick mock up that implements a Product, ProductRepository, and a ProductService. This code will be called from a simple console application that outputs the products to the display.


Listing 1: The model

01.public class Product
02.{
03.    public int Id { get; set; }
04.    public string Name { get; set; }    
05.    public string Description { get; set; }
06.    public double Price { get; set; }
07.}
08.public class ProductRepository
09.{
10.    public Product[] GetProducts()
11.    {
12.        List<Product> result = new List<Product>();
13.        for (int i = 1; i <= 10; i++)
14.        {
15.            result.Add(new Product()
16.                           {Description = "Product Description " + i, Id = i, Name = "Product " + i, Price = i});
17.        }
18.        return result.ToArray();
19.    }
20.}
21.public class ProductService
22.{
23.    public Product[] GetProducts(int Page, int RecordsPerPage)
24.    {
25.        Product[] result = new ProductRepository().GetProducts();
26.        return result.Skip((Page - 1) * RecordsPerPage).Take(RecordsPerPage).ToArray();
27.    }
28.}
We have a simple Product class that has an ID, Name, Description, and Price. Next we have a mocked up ProductRepository that can return a list of Products in a paged format. Now let's see the console code that outputs some products via a call to the ProductService to get a list of Products.

Listing 2: Console app

1.static void Main(string[] args)
2.{
3.    foreach (Product product in new ProductService().GetProducts(1,5))
4.    {
5.        Console.WriteLine("ID: " + product.Id + " Name: " + product.Name);
6.    }
7.    Console.ReadLine();
8.}
Now that we can see how this application works from a functional point of view a question comes up: How do we test this? Some might say that we can't test this but that is not technically true. Let's take a quick look at how we test non-injected code. We will start by creating a test for our ProductRepository. Given that this type of class connects to infrastructure in a real scenario this is more of an integration test than it is a unit test. But since this is a demo let's see a test that wraps around the repository.

Listing 3: Product Repository Tests

01.[TestFixture]
02.class ProductRepositoryTests
03.{
04.    [Test]
05.    public void GetProducts_ReturnsListOfProducts()
06.    {
07.        ProductRepository productRepository = new ProductRepository();
08.        Product[] products = productRepository.GetProducts();
09.        Assert.IsNotNull(products);
10.    }
11.}
As you can see this test simply gets a list of products from the ProductRepository and tests that the returned item is not null. For an integration test this might be acceptable. But this is not a real "unit" test though as this would not test only the code in a repository method but also all of the underlying code that touches the ORM, the database, etc.
Now let's see how we can test the ProductService given that it has a strong dependency on the ProductRepository.

Listing 4: Product Service Tests

01.[TestFixture]
02.public class ProductServiceTests
03.{
04.    [Test]
05.    public void GetProducts_NegativePageNumberPassed_ReturnsProducts()
06.    {
07.        Product[] products = new ProductService().GetProducts(-2, 5);
08.        Assert.IsNotNull(products);
09.        Assert.IsTrue(products.Length == 5);
10.    }
11.    [Test]
12.    public void GetProducts_UnrealPageNumberPassed_DoesntFail()
13.    {
14.        Product[] products = new ProductService().GetProducts(1000000000, 5);
15.        Assert.IsNotNull(products);
16.        Assert.IsNotNull(products.Length == 0);
17.    }
18.}
The ProductService tests read a bit more like a unit test. In these tests you can see that we are testing the GetProducts method off of the ProductService class. In the first test we are testing the state where a negative page number is passed to the method and we are still expecting the method to return some products. You can see this in that the common form of the class.method name is very clear in documenting the setup.
ClassName.MethodName_StateUnderTest_ExpectedResult
Or
ProductServiceTests.GetProducts_NegativePageNumberPassed_ReturnsProducts
This way when you run the unit tests in some form of a test runner you can easily see what is passing or failing and understand exactly what is going on with little to no additional research.

Now even though this runs and appears on the surface to be in good unit testing form...it really isn't! The reason why these tests are not good is that when we are testing our ProductRepository there is no real way to just test the repository (assuming that it actually touched a database somewhere and didn't actually spin up fake data). In the same vein our ProductService tests are also incapable of testing just the ProductService in that it has a direct dependency on the ProductRepository. This means that when we test the ProductService we are also executing code in the ProductRepository! That totally breaks the definition of a Unit Test...or testing a single unit of code.

Code that does use dependency injection

Now let's refactor this code a bit so that it follows the dependency injection pattern. To do this we first need to move any dependencies up and out of the code and into either a method as a parameter or into a constructor as a parameter. Either is technically acceptable. The loose rule here is that if more than one method in a class will need access to the dependency then put it in the constructor; otherwise put it in the method signature. We will stick to putting the dependencies into our constructor for a reason that I will discuss later.
Here is what our current code looks like now after refactoring out the dependencies.

Listing 5: Product Service

01.public class ProductService
02.{
03.    private ProductRepository _productRepository;
04.    public ProductService(ProductRepository productRepository)
05.    {
06.        _productRepository = productRepository;
07.    }
08.    public Product[] GetProducts(int Page, int RecordsPerPage)
09.    {
10.        Product[] result = _productRepository.GetProducts();
11.        return result.Skip((Page - 1) * RecordsPerPage).Take(RecordsPerPage).ToArray();
12.    }
13.}
Notice that we now have a new private field _productRepository of type ProductRepository and that this field is set through the constructor of the ProductService. Then when we need to use a ProductRepository we can use the _productRepository variable.
Does this make our code more testable? No...not really. Why? ...you might ask. Although we have injected the dependency you might notice that we are still directly dependent on the class at hand. In this case the ProductService is still directly dependent on the ProductRepository.
The key behind dependency injection is not only that the dependency is injected into the method but that the dependency is also abstracted away. To do this we will create interfaces that represent our current ProductService and ProductRepository. Then we can define the dependency around the interface rather than the type itself by specifying the interface as the type to be injected. Here is how that code looks.

Listing 6: Product Service

01.public class ProductService : IProductService
02.{
03.    private IProductRepository _productRepository;
04.    public ProductService(IProductRepository productRepository)
05.    {
06.        _productRepository = productRepository;
07.    }
08.    public Product[] GetProducts(int Page, int RecordsPerPage)
09.    {
10.        Product[] result = _productRepository.GetProducts();
11.        return result.Skip((Page - 1) * RecordsPerPage).Take(RecordsPerPage).ToArray();
12.    }
13.}
Now that the ProductService is only dependent on the interface that defines a ProductRepository we no longer need to worry about what is passed in as long as it implements the interface appropriately. This means that our code is a bit more testable now. Let's see how this changes our tests.

Listing 7: Product Service Tests

01.[TestFixture]
02.public class ProductServiceTests
03.{
04.    [Test]
05.    public void GetProducts_NegativePageNumberPassed_ReturnsProducts()
06.    {
07.        MockRepository mocks = new MockRepository();
08.        List<Product> testData = new List<Product>();
09.        for (int i = 0; i < 10; i++)
10.        {
11.            testData.Add(new Product() { Description = "Product Description", Id = i, Name = "Product Name", Price = 12.00 });
12.        }
13.        IProductRepository _mockRepository = mocks.StrictMock<IProductRepository>();
14.        Expect.Call(_mockRepository.GetProducts()).Return(testData.ToArray());
15.        mocks.ReplayAll();
16.        Product[] products = new ProductService(_mockRepository).GetProducts(-2, 5);
17.        Assert.IsNotNull(products);
18.        Assert.IsTrue(products.Length == 5);
19.    }
20.    [Test]
21.    public void GetProducts_UnrealPageNumberPassed_DoesntFail()
22.    {
23.        MockRepository mocks = new MockRepository();
24.        List<Product> testData = new List<Product>();
25.        for (int i = 0; i < 10; i++)
26.        {
27.            testData.Add(new Product() { Description = "Product Description", Id = i, Name = "Product Name", Price = 12.00 });
28.        }
29.        IProductRepository _mockRepository = mocks.StrictMock<IProductRepository>();
30.        Expect.Call(_mockRepository.GetProducts()).Return(testData.ToArray());
31.        mocks.ReplayAll();
32.        Product[] products = new ProductService(_mockRepository).GetProducts(1000000000, 5);
33.        Assert.IsNotNull(products);
34.        Assert.IsNotNull(products.Length == 0);
35.    }
36.}
You may have noticed in our new test code that we are no longer testing anything other than the ProductService. But since the ProductService does have a dependency on an IProductRepository we have to do something to provide it with a working implementation of IProductRepository. To do this we can use a tool such as RhinoMocks (or TypeMock) to create a mocked version of our IProductRepository. RhinoMocks allows you to dynamically mock out an object and then tell the framework to not only expect a call into the mocked object but also what that expected call should return.
As you can see in the above code we have had to do a bit more work to set up a test. But as expected we have not done anything more than what our tests would require. Most importantly we are not touching any code outside the bounds of what we want to test directly. In order to create a mock you generally need three things, the mocking framework reference, to define what call expected, and to define what is returned by the call. Obviously you can do more as needed but this is generally the minimum requirement. Once you have these things in place you can tell RhinoMocks to get ready for use by calling ReplayAll() (in RhinoMocks's case any ways).

Refactoring for dependency injection

How does all of this apply to our Knowledge Exchange project? Let's identify where we have issues first. Then we can address those issues one at a time until we have an entirely testable set up.

What needs to be refactored?

There is a big difference between our PostRepository in our project and the ProductRepository we used when discussing Dependency Injection above. Primarily that difference comes in that our PostRepository actually does communicate with the infrastructure using our ORM choice LINQ to SQL. We can fix this like any other dependency by pushing it up and having the Connection injected.
The PostService object is very similar to our ProductService in that it's only dependency currently is on the PostRepository. For this reason we will need to push up the PostRepository dependency which means that we will also need to push up the Connection dependency a bit further too.
The one other major bit of code that we really should have under test is our controllers. In this case we added our logic to our HomeController that comes with the MVC framework. In order to test the Index method of our HomeController we need to somehow push up our dependency on our PostService. This, more than the other two areas, will take quite a bit more to make happen. One thing at a time though!

Lets refactor it!

In order for us to refactor our PostRepository we need to push the Connection class up and out of the PostRepository. In order to do that we will need first create an interface that represents our Connection class.

Listing 8: IConnection.cs

1.public interface IConnection
2.{
3.    KEDataContext GetContext();
4.}
Once that is done we can then add a new parameter to our PostRepository's contructor.

Listing 9: PostRepository.cs

01.public class PostRepository
02.{
03.    private IConnection _connection;
04.    public PostRepository(IConnection connection)
05.    {
06.        _connection = connection;
07.    }
08.    public List<Domain.Post> GetAllPosts()
09.    {
10.        List<Post> result = new List<Post>();
11.        using(KEDataContext dc = _connection.GetContext())
12.        {
13.            result = dc.Posts.OrderByDescending(p => p.CreateDate).ToList();
14.        }
15.        return Mapper.Map<List<DataAccess.Post>, List<Domain.Post>>(result);
16.    }
17.}
Once this refactoring is complete we can then look to refactor our PostService. In this class we need to push up our PostRepository class to our PostService's constructor.

Listing 10: PostService.cs

01.public class PostService
02.{
03.    private IPostRepository _postRepository;
04.    public PostService(IPostRepository postRepository)
05.    {
06.        _postRepository = postRepository;
07.    }
08.    public List<Domain.Post> GetAllPosts()
09.    {
10.        return _postRepository.GetAllPosts();
11.    }
12.}
From here we need to address our controller. It should also have its dependencies injected as well so that we can test it in the same way that we can now test our PostRepository and PostService. Setting up injection for a controller is no different than adding injection to any other class. The only problem though is that we are not directly in charge of loading and controlling the Controllers - the framework is. In order to apply injection to a Controller we will have to jump through a few hoops that we will cover in the next article.
For now we will modify our HomeController so that it can take care of our dependencies. While this means that we won't be able to test our HomeController (which means that the refactoring is not totally complete) we will be able to run our application and write some tests for the other parts of our code. We will finish this round of refactoring in the next chapter.

Writing our tests

We can start writing our tests around the PostRepository. Keep in mind that this is not really a UnitTest as much as it is an IntegrationTest. There really isn't anything in the PostRepository that can be unit tested at this particular time. And that is ok. Here is the integration test which actually goes to the database and fetches some data. In the test we simply verify that some data came back.

Listing 11: PostRepositoryTests.cs

01.[TestFixture]
02.public class PostRepositoryTests
03.{
04.    [Test]
05.    public void GetAllPosts_ReturnsPosts()
06.    {
07.        AutoMapperBootStrapper.Initialize();
08.        PostRepository _postRepository = new PostRepository(new Connection());
09.        var results = _postRepository.GetAllPosts();
10.        Assert.IsNotEmpty(results);
11.    }
12.}
Notice that in the beginning of our test we have to run the AutoMapperBootStrapper to get the mapping functionality to work in our repository. Next we create an instance of our PostRepository which takes an instance of Connection. Then we call the GetAllPosts() method which returns a list of Posts into our results variable. Then we can run a test to check that the results list is not empty. Something not seen here and generally not seen in a standard unit test is that we also had to add an app.config file with our connection string. Being an integration test this test does reach out and touch our database.
Next we can write a test for our PostService. This class is a little different to test in that it has a dependency on the PostRepository (or IPostRepository) but it is not much different from what was covered in our initial conversation. In this test you will notice that we initialize a MockRepository object first thing. From there we generate a list of Posts for our expected result. Then we spin up a new instance of IPostRepository using the RhinoMocks framework. Next we set up the expected call and return values. Then we are ready to initialize an instance of our IPostService which we pass in the mocked PostRepository. Finally we tell the RhinoMocks framework to get ready for our tests to call into it by calling the ReplayAll() method. Now we are ready to start our test. We set up a new list of Domain.Posts to hold our testResult which we populate by making a call to our PostService.GetAllPosts() method. If all works well we should have a list of Domain.Post items that we can test against.

Listing 12: PostServiceTests.cs

01.[TestFixture]
02.public class PostServiceTests
03.{
04.    [Test]
05.    public void GetsAllPosts_GetsPosts()
06.    {
07.        MockRepository mocks = new MockRepository();
08.        List<AndrewSiemer.KnowledgeExchange.Domain.Post> posts = new List<AndrewSiemer.KnowledgeExchange.Domain.Post>();
09.        for (int i = 0; i < 10; i++) { posts.Add(new AndrewSiemer.KnowledgeExchange.Domain.Post() { Body = "Post Body", CreateDate = DateTime.Now, LastUpdated = DateTime.Now, PostID = i + 1, ProfileID = 1, Title = "Post Title" }); }
10.        IPostRepository _postRepository = mocks.StrictMock<IPostRepository>();
11.        Expect.Call(_postRepository.GetAllPosts()).Return(posts);
12.        IPostService _postService = new PostService(_postRepository);
13.        mocks.ReplayAll();
14.        List<AndrewSiemer.KnowledgeExchange.Domain.Post> testResult = _postService.GetAllPosts();
15.        Assert.IsNotEmpty(testResult);
16.    }
17.}
Keep in mind that these tests are pretty lame! Since this is demo-ware we don't have a whole lot of moving parts in here to test. The PostRepository does reach out to the database so that is a good test. But the PostService is pretty much a pass through set of plumbing for expansion on later. If there were more moving parts in the PostRepository we would also want to create a UnitTest for the PostRepository that doesn't go to the database but instead tests the guts of the repository itself.

Analysis

The mere fact that we now have code that can be tested means that we have made some huge headway. We do have to keep in mind that our HomeController is not yet testable. More than even that we are instantiating all of our dependencies in the HomeController as well which may be even worse. No worries though we will remedy that soon enough. This issue of our HomeController doing what it does though has added an even more painful issue to our system in that our presentation tier now has a dependency on our data access (otherwise the HomeController wouldn't know how to create an instance of the PostRepository). We will fix that in the next article too!
Take a look at our dependency graph below. For the most part things are working out just as we would expect them too. Short of the web to dataaccess issue all is going the right direction! Do take note that our DataAccess.Tests and Domain.Tests items have no usage defined as neither have anything that can be tested just yet.


Pros

Once everything can follow along with the Dependency Injection pattern we will be able to have all of our code under test. Using this pattern not only makes our code more testable but also more flexible. Once everything is dependent only on abstractions we can swap in and out whatever we like whenever we like. We will see the use and power of this the further we go.

Cons

I have never heard of a con that has popped up due to the simple implementation of Dependency Injection. Taking a dependency on an Inversion of Control container (such as StructureMap which we will introduce in the next article) may provide a performance degradation but just following this pattern by itself won't hurt us!

Comparison Chart

Table 1: Comparison Chart

Coding Concepts Yes Sorta No
Fast/Easy to develop: Can we generate the end product quickly? X
Testable: Can we write tests around the majority of the projects code? X
Flexible for refactoring: Can we easily refactor the code base to add new concepts? X
Well abstracted: Do the users of your code only know what they need too? X
Well encapsulated: Can you change the internals of code without impacting the users of that code? X
Separation of concerns? Is your code well compartmentalized and only doing what it needs to? X
DRY? Does your code follow the "Don't repeat yourself motto?" X
SOLID? Does this code comply with the SOLID principles?
S: Single Responsibility Principle - there should never be more than one reason for a class to change
O: Open Closed Principle - should be open for extension but closed for modification
L: Liskov Substitution Principle - functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it
I: Interface Segregation Principle - clients should not be forced to depend upon interfaces that they do not use
D: Dependency Inversion Principle - high level modules should not depend upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions.
X
X
X
X
X
X
Swappable? Can you swap out an entire layer down the road? X
Distributable? Can you push complex processing of logical areas to a separate server easily to offload computing cycles and scale? X

Summary

In this article we have walked through a discussion of how code that does not follow the dependency injection pattern is not as testable as code that does. With an understanding of how dependency injection works and why it is important we were then able to walk through the majority of our code to refactor towards the dependency injection pattern. Once our code was refactored to implement dependency injection we were then able to write some tests around our code. We did find that towards the end of the article there were parts of our code that we do not have total control over and therefore were unable to convert it to a testable format. With these issues identified we were able to discuss some approaches to fix them.
In the next article we will discuss how we can enhance the power of the Dependency Injection pattern by implementing an Inversion of Control container. We will discuss what an IoC container can be used for and how it works. Then we will look at implementing an Inversion of Control container in our code. We will specifically implement the IoC container StructureMap. Once StructureMap is plugged in and working we will once again refactor our code to take advantage of StructureMap. And with that refactoring completed we can then address the Controller issue that we found in this article by creating a custom ControllerFactory that takes care of locating and returning a custom controller but also takes care of instantiating our dependencies in an automated fashion using StructureMap.