A Taste of Dependency Injection, Testing, and Mocking

by EFVincent on 05/27/2011

My last post provided a brief introduction into dependency injection. To review, the example included a data provider for Employee objects, which included a feature to return the object corresponding to the currently logged in user. In the end the following interfaces were defined:

IDataProvider – the function is obvious from the name. One implementation, the DevDataProvider, uses a static List<Employee> as a data store.

IIdentityService – describes a service that supplies the current identity. What current is depends on the implementation of course. A concrete WindowsIdentService defines current as the currently logged in Windows user. The TestIdentService implementation always returned the same username, which is useful for testing as we will see.

ILogService – describes a simple logging service. The ConsoleLogService implementation prints logs to the console.

Dependency Injection &Testing

For this post I’ve added a standard MSTest project and a couple of tests for the data provider. The use of dependency injection patterns in the design of this simple example allows us to easily isolate the code under test.

static IContainer afContainer;

[ClassInitialize]
public static void TestInit(TestContext ctx) {
    var idSvc = A.Fake<IIdentService>();
    A.CallTo(() => idSvc.GetCurrentUserName())
        .Returns("FAKE-ID");

    var bldr = new ContainerBuilder();
    bldr.RegisterInstance(idSvc);
    bldr.RegisterInstance(A.Fake<ILogService>());
    bldr.RegisterType<DevDataProvider>().As<IDataProvider>();
    afContainer = bldr.Build();
}

The test class has a static DI container instance, initialized in the class initializer. I’m using FakeItEasy to create a fake IIdentService at line five. Like six tells the FakeItEasy framework what to return when the GetCurrentUserName() method is called on the fake ident service. Having a fixed response makes testing the data provider a piece of cake.

I then register the fake ident service as well as a fake log service. For the log service, we don’t need to specify any behavior for the methods. The FakeItEasy framework will effectively sink any calls to the methods of the fake log service, which is fine for this test.

Lastly the data provider we want to test is registered with the DI container builder, and then container is built. The tests go on to use the DI container to resolve an instance of the data provider. The DI container will configure the data provider’s dependencies for a log service and an identity service with the fakes we built.

[TestMethod()]
public void GetCurrentEmployeeTest() {
    var e = new Employee { WindowsUsername = "FAKE-ID" };
    var dal = afContainer.Resolve<IDataProvider>();
    dal.AddEmployee(e);
    var result = dal.GetCurrentEmployee();
    Assert.AreEqual(e.WindowsUsername, result.WindowsUsername);
}

This is just a small example of using a DI container in combination with a mock / fake framework for testing. The AutoFac DI container can handle much more complex scenarios than what we’ve thrown at it here. The same is true for the FakeItEasy component. Both of these components are well used, well maintained open source projects. You can find lots of documentation and examples for both. Or you can use any number of other DI containers and mocking frameworks to achieve equivalent results.

The source code for the example is available here, and the blog entry the precedes this one is available here.

{ 2 trackbacks }

Practical Dependency Injection 101
06/02/2011 at 1:53 pm
DI – Constructor Injection, Bootstrapping
06/24/2011 at 2:06 pm

{ 0 comments… add one now }

Leave a Comment

Previous post: Practical Dependency Injection 101

Next post: DI – Constructor Injection, Bootstrapping