Wednesday, November 5, 2014

Integration testing with Chill


Unit testing means testing software components in isolation. This can be a powerful technique to validate some complex pieces of logic.

However, if you follow the Single Responsibility Principle, you’ll find that many of your components hardly contain enough logic to warrant unit testing. For example, a webapi controller might just take a message object, validate it using a validator component, map it to an internal data format, and then hand it off to yet another component for validation. All it does is chain some components together. If you dogmatically try to unit test each of these components in isolation, you’ll end up with a system that becomes difficult to architecturally.

In those cases, integration tests make much more sense. You want to make sure that the entire collection of components work well together, not that each individual piece does what it needs to do.

Note, unit tests do make a lot of sense for some (sufficiently complex) components. As always, it’s important to know what technique to apply when.

Integration testing does have it’s own set of challenges. Ideally, you’d like to start with a pristine environment, prepare a certain ‘start situation’, then execute a test and validate the result. In the next couple of weeks, I’ll put out a sample application that demonstrates some of these capabilities.

But for now, I can demonstrate how you can setup a container in exactly the same way that you’d do in your application.

Suppose you have several registrations you’d like to make in your container. Here, I’m doing that in Autofac in a module:

   2: public class CustomAutofacModule : Module
   3: {
   4:     protected override void Load(ContainerBuilder builder)
   5:     {
   6:         builder.RegisterType<TestService>().As<ITestService>();
   7:         builder.RegisterType<TestSingleton>().SingleInstance();
   8:         base.Load(builder);
   9:     }
  10: }

Ok, great.. now how would you set up a chill container that uses this? The easiest way is to create a custom container, that derives from  AutofacChilContainer. 

   1: /// <summary>
   2: /// You can define 'non mocking' with all the type registrations that you would otherwise in your application. 
   3: /// This can either be done in the App. This class also creates a single 'parent' container and then child containers
   4: /// per test. 
   5: /// </summary>
   6: internal class AutofacContainerWithCustomModule : AutofacChillContainer
   7: {
   8:     private static ILifetimeScope staticContainer;
   9:     private static object syncRoot = new object();
  10:     public AutofacContainerWithCustomModule()
  11:         : base(CreateContainer())
  12:     {
  14:     }
  15:     /// <summary>
  16:     /// This method creates the Autofac container and registers the custom type 
  17:     /// </summary>
  18:     /// <returns></returns>
  19:     private static ILifetimeScope CreateContainer()
  20:     {
  21:         if (staticContainer == null)
  22:         {
  23:             lock (syncRoot)
  24:             {
  25:                 if (staticContainer == null)
  26:                 {
  27:                     var builder = new ContainerBuilder();
  28:                     builder.RegisterModule<CustomAutofacModule>();
  29:                     staticContainer = builder.Build();
  30:                 }
  31:             }
  32:         }
  33:         return staticContainer.BeginLifetimeScope();
  34:     }
  35: }

This way, Chill will setup your Autofac registrations once. Very welcome if you’re registering expensive things such as NHibernate SessionFactories. It will also setup up two lifetime scopes. One per test run (since it’s a static singleton) and one child scope per test. This child scope can be customized to your hearts content.

Now if you wish to use this container, you can set the following attribute on class or assembly level:


1 comment: