Dot Net Core Using the IOC Container

I’ve talked about Inversion Of Control in previous posts, but I’m going to go over it again.  If you’re new to IOC containers, breaking dependencies and unit testing, then this is the blog post you’ll want to read.  So let’s get started…

Basic Concept of Unit Testing

Developing and maintaining software is one of the most complex tasks ever performed by humans.  Software can grow to proportions that cannot be understood by any one person at a time.  To compound the issue of maintaining and enhancing code, there is the problem that one small change in code can affect the operation of something that seems unrelated.  Engineers that build something physical, like say a jumbo jet can identify a problem and fix it.  They usually don’t expect a problem with the wing to affect the passenger seats.  In software, all bets are off.  So there needs to be a way to test everything when a small change is made.

The reason you want to create a unit test is to put in place a tiny automatic regression test.  This test is executed every time you change code to add an enhancement.  If you change some code, the test runs and ensures that you didn’t break a feature that you already coded and tested previously.  Each time you add one feature, you add a unit test.  Eventually, you end up with a collection of unit tests covering each combination of features used by your software.  These tests ride along with your source code forever.  Ideally, you want to always regression test every piece of logic that you’ve written.  In theory this will prevent you from breaking existing code when you add a new enhancement.

To ensure that you are unit testing properly, you need to understand coverage.  Coverage is not everything, but it’s a measurement of how much of your code is covered by your unit tests and you should strive to maximize this.  There are tools that can measure this for you, though some are expensive.  One aspect of coverage that you need to be aware of is the combination “if” statement:

if (input == 'A' || input =='B')
{
    // do something
}

This is a really simple example, but your unit test suite might contain a test that feeds the character A into the input and you’ll get coverage for the inner part of the if statement.  However, you have not tested when the input is B and that input might be used by other logic in a slightly different way.  Technically, we don’t have 100% coverage.  I just want you to be aware that this issue exists and you might need to do some analysis of your code coverage when you’re creating unit tests.

One more thing about unit tests and this is very important to keep in mind.  When you deploy this software and bugs are reported, you will need to add a unit test for each bug reported.  The unit test must break your code exactly the way the bug did.  Then you fix the bug and that prevents any other developer from undoing your bug fix.  Of course, your bug fix will be followed by another unit test suite run to make sure you didn’t break any thing else.  This will help you make forward progress in your quest for bug-free or low-bug software.

Dependencies

So you’ve learned the basics of unit test writing and you’re creating objects and and putting one or more unit tests on each method.  Suddenly you run into an issue.  Your object connects to a device for input.  An example is that you read from a text file or you connect to a database to read and write data.  Your unit test should never cause files to be written or data to be written to a real database.  It’s slow, the data being written would need to be cleaned out when the test completed.  What if the tests fail?  Your test data might still be in the database.  Even if you setup a test database, you would not be able to run two versions of your unit tests at the same time (think of two developers executing their local copy of the unit test suite).

The device being used is called a dependency.  The object depends on the device and it cannot operate properly without the device.  To get around dependencies, we need to create a fake or mock database or a fake file I/O object to put in place of the real database or file I/O when we run our unit tests.  The problem is that we need to somehow tell the object under test to use the fake or mock instead of the real thing.  The object must also default to the real database or file I/O when not under test.

The current trend in breaking dependencies involves a technique called Inversion Of Control or IOC.  What IOC does is allow us to define all object create points at program startup time.  When unit tests are run, we substitute the objects that perform database and I/O functions with fakes.  Then we call our objects under test and the IOC system takes care of wiring the correct dependencies together.  Sounds easy.

IOC Container Basics

Here are the basics of how an IOC container works.  I’m going to cut out all the complications involved and keep this super simple.

First, there’s the container.  This is a dictionary of interfaces and classes that is used as a lookup.  Basically, you create your object and then you create a matching interface for your object.  When you call one object from another, you use the interface to lookup which class to call from your object.  Here’s a diagram of object A dependent on object B:

Here’s a tiny code sample:

public class A
{
  public void MyMethod()
  {
    var b = new B();

    b.DependentMethod();
    }
}

public class B
{
  public void DependentMethod()
  {
    // do something here
  }
}

As you can see, class B is created inside class A.  To break the dependency we need to create an interface for each class and add them to the container:

public interface IB
{
  void DependentMethod();
}

public interface IA
{
  void MyMethod();
}

Inside Program.cs:

var serviceProvider = new ServiceCollection()
  .AddSingleton<IB, B>()
  .AddSingleton<IA, A>()
  .BuildServiceProvider();

var a = serviceProvider.GetService<IA>();
a.MyMethod();

Then modify the existing objects to use the interfaces and provide for the injection of B into object A:

public class A : IA
{
  private readonly IB _b;

  public A(IB b)
  {
    _b = b;
  }

  public void MyMethod()
  {
    _b.DependentMethod();
  }
}

public class B : IB
{
  public void DependentMethod()
  {
    // do something here
  }
}

The service collection object is where all the magic occurs.  This object is filled with definitions of which interface will be matched with which class.  As you can see by the insides of class A, there is no more reference to the class B anywhere.  Only the interface is used to reference any object that is passed (called injected) into the constructor that conforms to IB (interface B).  The service collection will lookup IB and see that it needs to create an instance of B and pass that along.  When the MyMethod() is executed in A, it just calls the _b.DependendMethod() method without worrying about the actual instance of _b.  What does that do for us when we are unit testing?  Plenty.

Mocking an Object

Now I’m going to use a NuGet package called Moq.  This framework is exactly what we need because it can take an interface and create a fake object that we can apply simulated outputs to.  First, lets modify our A and B class methods to return some values:

public class B : IB
{
  public int DependentMethod()
  {
    return 5;
  }
}

public interface IB
{
  int DependentMethod();
}

public class A : IA
{
  private readonly IB _b;

  public A(IB b)
  {
    _b = b;
  }

  public int MyMethod()
  {
    return _b.DependentMethod();
  }
}

public interface IA
{
  int MyMethod();
}

I have purposely kept this so simple that there’s nothing being done.  As you can see, DependentMethod() just returns the number 5 in real life.  Your methods might perform a calculation and return the result, or you might have a random number generator or it’s a value read from your database.  This example just returns 5 and we don’t care about that because our mock object will return any value we want for the unit test being written.

Now the unit test using Moq looks like this:

[Fact]
public void ClassATest1()
{
    var mockedB = new Mock<IB>();
    mockedB.Setup(b => b.DependentMethod()).Returns(3);

    var a = new A(mockedB.Object);

    Assert.Equal(3, a.MyMethod());
}

The first line of the test creates a mock of object B called “mockedB”.  The next line creates a fake return for any call to the DependentMethod() method.  Next, we create an instance of class A (the real class) and inject the mocked B object into it.  We’re not using the container for the unit test because we don’t need to.  Technically, we could create a container and put the mocked B object into one of the service collection items, but this is simpler.  Keep your unit tests as simple as possible.

Now that there is an instance of class A called “a”, we can assert to test if a.MyMethod() returns 3.  If it does, then we know that the mocked object was called by object “a” instead of a real object of class A (since that always returns a 5).

Where to Get the Code

As always you can get the latest code used by this blog post at my GitHub account by clicking here.

 

Dependency Injection and IOC Containers

Summary

I’ve done quite a few posts on unit testing in the past.  I keep a list of subjects that I would like to blog about so I have a ready list to choose from.  My list of unit testing subjects is getting large and it’s time to clear the spindle.  So in this post I’m going to do some deep diving on Dependency Injection and introduce Inversion Of Control using Autofac.

The Die Roller

I created a simple program a while back that does a die roll (you can find it by clicking here). I had hoped to write some follow up posts about other methods that can be used to get around the problem of object dependency, but other blog subjects grabbed my interest and took up my time.  So now I’m going to go back and discuss other techniques that I know in order to break or eliminate dependencies in objects.

First, I’m going to show a technique that uses a singleton.  The idea behind this design pattern is to provide a default object that will self-instantiate when it is called from the main program, but provide an entry point (a setter) that will allow the object to be overridden by a fake object in a unit test before the object under test is called.  I’ve blogged about this technique in this post where I described a technique to design a caching system. 

The base object looks like this:

public abstract class DieRollerBase
{
	public static DieRollerBase _Instance;

	public static DieRollerBase Instance
	{
		get
		{
			if (_Instance == null)
			{
				_Instance = new DieRoller();
			}

			return _Instance;
		}

		set
		{
			_Instance = value;
		}
	}

	public static int DieRoll()
	{
		return Instance.ReturnDieRoll();
	}

	public abstract int ReturnDieRoll();
}

The die roller object, which is run inside the main program looks like this:

public class DieRoller : DieRollerBase
{
	private Random RandomNumberGenerator = new Random(DateTime.Now.Millisecond);

	public override int ReturnDieRoll()
	{
		return RandomNumberGenerator.Next() % 6;
	}
}

As you can see, the base class instantiates a new DieRoller() object, instead of a DieRollerBase object.  What happens is the main program will call the die roller using the following syntax:

int result = DieRoller.DieRoll();

The call to the method DieRoll() is static, but it calls the instance method called ReturnDieRoll() which is implemented inside the sub-class, not the base class.  The reason for doing this is that we can override the DieRoll() class with a fake class like this:

public class FakeDieRoller : DieRollerBase
{
	private static int _NextDieRoll = 0;
	private static List _SetDieRoll = new List();
	public static int SetDieRoll
	{
		get
		{
			int nextDieRoll = _SetDieRoll[_NextDieRoll];
			_NextDieRoll++;
			if (_NextDieRoll >= _SetDieRoll.Count)
			{
				_NextDieRoll = 0;
			}

			return nextDieRoll;
		}
		set
		{
			_SetDieRoll.Add(value);
		}
	}

	public static void ClearDieRoll()
	{
		_SetDieRoll.Clear();
		_NextDieRoll = 0;
	}

	public override int ReturnDieRoll()
	{
		return SetDieRoll;
	}
}

Using the setter of the base class for the instance, we can do this in our unit test:

DieRoller.Instance = new FakeDieRoller();
Any method calling the die roller will end up executing the fake class instead of the default class.  The reason for doing this is so we can load the dice by stuffing “known” die roll numbers into the dice before calling our object under test.  Then we can get predictable results from objects that use the random die roll object.


Analysis

In my earlier blog post I created a die roller class that looked like this:

public static class DieRoller
{
	private static Random RandomNumberGenerator = new Random(DateTime.Now.Millisecond);

	public static int DieRoll()
	{
		if (UnitTestHelpers.IsInUnitTest)
		{
			return UnitTestHelpers.SetDieRoll;
		}
		else
		{
			return RandomNumberGenerator.Next() % 6;
		}
	}
}


The injection took place using the UnitTestHelpers object.  This tests if the startup dll was a microsoft test object and then executed a built-in fake die.  This is not a clean technique for unit testing since there is some test code compiled into the distributed dlls.  Mainly, the UnitTestHelpers.SetDieRoll method.

The singleton method is much cleaner, because the fake object can be created inside the unit test project and not distributed with the production dlls.  Therefore the final code will not contain the fake die object or any of the test code.  The problem with singletons is that they are complicated to design.

There is a better technique.  It’s called Inversion Of Control or IOC.  The idea behind inversion of control is that objects are created independent of each other, then they are “wired” together at program initialization time.  Unit tests can link fake objects before the tests are executed, which automatically bypasses the dependent objects that are not under test.  This approach is cleaner and I’m going to show the die roller using the Autofac IOC container.

Setting up the Solution

Autofac has an object called the container.  The container is like a dictionary storage place where all the classes and interfaces are stored when the program is initialized.  Then the resolve command uses the container information to match which class is setup for each interface.  Inside your class, you’ll call the resolve command and pass the interface, without any reference to the object class itself.  This allows Autofac to set which class will be used for the interface when is needed.  By doing this, we can setup a different class (like a fake class) inside a unit test and the object under test will call the resolve command with the same interface but the fake object will already be instantiated by Autofac to be used.

So here are the projects I used in my little demo program:

Container
DieRollerAutoFac
DieRollerLibrary
GameLibrary
DieRollerTests

The program itself will start from the DieRollerAutoFac project.  This is just a console application that initializes the IOC container and runs the game.  The IOC container is stored in a static class called IOCContainer and it’s inside the “Container” library.  The reason I structured it this way is so I can use the container for the program and I can use the container for the unit tests.  I also needed the container for the game class when it performs the resolve operation.  So the container must be in a different project to keep it from being dependent on the game class or the main program.
Next, I created the die roller class and interface inside it’s own project.  This could be contained inside the GameLibrary project, but I’m going to pretend that we want to isolate modules (i.e. dlls).

Next we need to wire everything up.  If you download the sample code and look at the main program, you’ll see this piece of code:

var builder = new ContainerBuilder();
builder.RegisterType<DieRoller>().As<IDieRoller>();
IOCContainer.Container = builder.Build();


This is the code that builds the container.  Once the container is built, it can be used by any object in the program.

Inside the game class the container is used to resolve the die object:

public class Game
{
	public int Play()
	{
		using (var scope = IOCContainer.Container.BeginLifetimeScope())
		{
			var die = scope.Resolve();

			return die.DieRoll();
		}
	}
}

To substitute a fake die class in your unit tests, you can do this:

var builder = new ContainerBuilder();
builder.RegisterType<FakeDieRoller>().As<IDieRoller>();
IOCContainer.Container = builder.Build();


Checklist of IOC container rules:
1. Use the NuGet manager to install Autofac.  
2. Make sure you create an interface for each object you intend to use in your IOC container.
3. Setup a container creator in your unit tests with fake or mock objects.

Where to get the code

As always I have posted all the code from this blog post.  You can download the source by clicking here