[C# Design Patterns] The Dependency Injection Pattern

This post will demonstrate the Dependency Injection (DI) design pattern. Dependency Injection is also known as Dependency Inversion, or Inversion of Control (IoC).

 

Video version here:

 

What it is

Dependency Injection is a special use of the Strategy Pattern. If you aren’t familiar with it, please see this post on the Strategy Pattern first.

With the Strategy Pattern, you pass an object into a function. The function uses the passed-in object to perform some action. You can pass in different objects, to perform the action differently – as long as the object matches the specified interface.

With Dependency Injection, the action you want the Strategy object to perform is one where the function needs to use an external resource – like a database, the file system, a web service, etc.

The reason you would do this is to let you write automated tests for the function, without needing to access the external resource. That way, you don’t need to worry if the database/file system/web service is working the way your automated test needs it to work.

 

Examples

This example will use a “Player” class, for a game. It has a CreateNewPlayer function, which does three things:

  1. Raise an error if the player name parameter is an empty string.
  2. Raise an error if the player name already exists in the database.
  3. If there weren’t any errors, add the player to the database.

Notice that #2 and #3 need to access the database.

 

Non-Pattern Version

Player.cs

The CreateNewPlayer function performs the first thing we need it to do – raise an error if the “name” parameter is empty.

Then, it creates a PlayerDataMapper object (see the code below), to do the next two things we need it to do – interact with the database.

 

PlayerDataMapper.cs

This has a problem, if we want to create automated tests for the CreateNewPlayer function.

For the tests to pass, we need to have a running database. We would want to create a test for when the player name exists in the database, and when it does not exist. So, we would need to add the record (or delete it) before running the different tests.

Also, if we have many tests that use the database, it will take a long time to run them and know if the tests pass – or not.

 

TestPlayer.cs

So, in this unit test class, we can only test the failure condition for when the name parameter is an empty string. Any other test requires a working database, with specific data in it (or not in it).

 

Pattern Version

 

In order to create unit tests, which are tests that do not need external resources (such as a database, the file system, etc.), I’ll convert CreateNewPlayer to use Dependency Injection.

That way, I can pass in a “mock” PlayerDataMapper object for CreateNewPlayer to use. That mock object won’t need a database, and can be set up to return whatever results the unit tests need.

 

IPlayerDataMapper.cs

This interface defines the functions that a PlayerDataMapper objects needs to perform – the same functions that were used in the non-pattern version.

 

PlayerDataMapper.cs

This class is the same as in the non-pattern version, except we declare that it implements IPlayerDataMapper.

 

Player.cs

This class is similar to the non-pattern version. However, the CreateNewPlayer function has a second parameter – an object that implements IPlayerDataMapper.

NOTE: The “= null” after the parameter (if you aren’t familiar with that) means the parameter is optional. If the function is called with one parameter, it will pretend it received a “null” for the “playerDataMapper” parameter.

If the playerDataMapper parameter is null, the function will create a new (non-mock) PlayerDataMapper object to use. If an object is passed in for the parameter, the function will use that object.

This is the dependency injection.

Instead of CreateNewPlayer always using its own PlayerDataMapper object, we can pass in (inject) an object that implements IPlayerDataMapper.

 

MockPlayerDataMapper.cs

This class implements IPlayerDataMapper. I’ll can create an instance of it and pass that into the CreateNewPlayer function.

However, the methods in this “mock” class do not touch the database. Plus, we can configure the PlayerNameExistsInDatabase() function to return a true or false – whichever result the unit test needs.

NOTE: For real unit tests, I would use a mocking library (such as Moq), instead of manually creating mock classes. That is much faster, and simpler, than manually creating mock objects.

 

TestPlayer.cs

Now, I can create unit tests for all possible paths through the function.

I would still want to test that the code works with a database. However, this is a good way to test the function – especially if there were more non-database validations in it.

 

Where I’ve found it useful

I’ve used this to create many automated unit tests.

With a large program, it would take weeks, or months, to manually test all possible paths through the code. With automated tests, that use mock objects, you can usually test every possible path in a few minutes.

I’ve mostly used this pattern to let me create automated tests for my code that uses external resources (the file system, a database, a web service, etc.)

If you want to use dependency injection with a large application, consider using an Inversion of Control (IOC) library, such as Autofac, Castle Windsor, Ninject, or StructureMap.

These libraries can make it easier to do dependency injection. However, they do require some configuration, or registration, of your application’s classes. It’s usually easy to do – although, if you haven’t added any new classes to your project lately, you need to remember how/where to do the configuration.

They can also cause a problem if you use any static analysis (code quality) tools on your source code. They may not recognize that your objects are instantiated by the IoC library, and think you have unused classes that should be removed.