Increasing Testability

Posted by Joe Wilson on Sunday, March 7, 2010 4:30 PM

Testa-what?

I don't know if "testability" is a word, but if Bud Light can make up "drinkability", maybe it should be.  I'm talking about how pliant your code is to testing.  If you're doing TDD or BDD, the code you write is testable by definition. 

But if you're going the other way, and coding first or testing legacy code (any code not already under test), you've probably run into code that was hard to test and felt like giving up.  Some of the most common hurdles for testability are not coding to abstractions and not decoupling dependencies.  Here's how to get around that.

The problem

Here's a garden variety Order class with a ProcessOrder method:

public class Order
{
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public string Email { get; set; }
  public decimal Total { get; set; }

  public bool ProcessOrder()
  {
    var result = false;
      
    // Validate order
    if (!string.IsNullOrEmpty(this.Email) && this.Total > 0)
    {
      // Send order confirmation email
      var emailService = new EmailService();
      var emailSendResult = emailService.SendOrderConfirmationEmail(this);

      if (emailSendResult == true)
      {
        // Do more order processing...

        result = true;
      }
    }

    return result;
  }
}

And here's the test:

[Test]
public void Should_return_true_when_using_good_order_values()
{
  // Arrange
  var order = new Order();
  order.FirstName = "Joe";
  order.LastName = "Wilson";
  order.Email = "real_email_address@volaresystems.com";
  order.Total = 123.00m;

  // Act
  // Watch out!  Don't run this or it will send real emails!
  var result = order.ProcessOrder();

  // Assert
  Assert.That(result, Is.True);
}

We need to call the SendOrderConfirmationEmail method in the EmailService class.  But if our test calls ProcessOrder, there is no way to avoid calling the live emailing method as it's coded now.

How can we test the logic in the ProcessOrder method without sending out a real email?

Code to Abstractions

First, we need to code to an abstraction of EmailService, not to the concrete class itself.  So let's create an interface around EmailService:

public interface IEmailService
{
    bool SendOrderConfirmationEmail(Order order);
}

Then change the EmailService class to implement this new interface.  Visual Studio 2008 and ReSharper make this easy. 

This will let us change our test later to use a fake version of IEmailService instead of the real one.

Decouple and Invert your Dependencies

The next problem is we're creating an instance of the EmailService class in the ProcessOrder method.  Anytime you use "new" in your code, you're probably introducing a dependency and reducing testability. 

The fix is to let the caller create the instance and tell the class or method being called which instance to use.  I am using a private field with constructor injection to set the field instance.  Note we're also now coding to the interface IEmailService instead of the instance EmailService.

Here's the full Order method using the private field to call the SendOrderConfirmationEmail method on IEmailService inside the ProcessOrder method.

public class Order
{
  private readonly IEmailService _emailService;

  public string FirstName { get; set; }
  public string LastName { get; set; }
  public string Email { get; set; }
  public decimal Total { get; set; }

  public Order(IEmailService emailService)
  {
      _emailService = emailService;
  }

  public bool ProcessOrder()
  {
    var result = false;
      
    // Validate order
    if (!string.IsNullOrEmpty(this.Email) && this.Total > 0)
    {
      // Send order confirmation email
      //var emailService = new EmailService(); // Created outside this class now
      var emailSendResult = _emailService.SendOrderConfirmationEmail(this);

      if (emailSendResult == true)
      {
        // Do more order processing...

        result = true;
      }
    }

    return result;
  }
}

Dependencies can be very hard to spot, but it's critical to tease them out of your code to increase testability.  They can even come from things as innocuous as DateTime.  If you're code relies on DateTime.Now, how will you write unit tests for your logic without changing your system clock when you run the test?  It's simpler to have the caller pass in the DateTime value and have the method do the calculations based on whatever value it is given.

Make a Fake

Now that we've got testable code, we can make a fake EmailService and update our test.

First, create the FakeEmailService class implementing the IEmailService we created earlier.  We need the SendOrderConfirmationEmail method to return true to simulate an email being successfully sent.

public class FakeEmailService : IEmailService
{
  public bool SendOrderConfirmationEmail(Order order)
  {
    return true;
  }
}

You could also use a mocking framework like Moq or Rhino Mocks for this, but a homemade fake is easy, too.

Now we're ready to update our test to use the fake and inject it into the Order constructor:

[Test]
public void Should_return_true_when_using_good_order_values()
{
    // Arrange
    var emailService = new FakeEmailService();
    order = new Order(emailService);
    order.FirstName = "Joe";
    order.LastName = "Wilson";
    order.Email = "real_email_address@volaresystems.com";
    order.Total = 123.00m;

    // Act
    var result = order.ProcessOrder();

    // Assert
    Assert.That(result, Is.True);
}

Last step

We've refactored the Order class so the caller sends the IEmailService instance to it.  That makes sense for the test, but what about the real code?

I typically use an IOC container like Structure Map or Castle Windsor to hold and resolve an in-memory dictionary of interfaces and class instances.  You wire it up at application startup and when you call something that needs IEmailService, it creates an instance of EmailService for you.

If you're working with legacy code and can't use and IOC container, you also can add a no arg constructor like this:

public Order() : this(new EmailService())
{
}

public Order(IEmailService emailService)
{
    _emailService = emailService;
}

Your legacy code keeps calling the no arg constructor like it used to, and any new code and your test code use the constructor with IEmailService dependency passed in.

Wrap up

If you code isn't testable, you won't test it.  If you're working with legacy code or writing tests after coding, you can use these techniques to pull out external dependencies so they can be faked for testing. 

You can have it all: testable code, unit tests around that code, and no broken legacy code.  Mmmm.Testability.Drink it in!

Tags: , ,
Categories: Technical


kick it on DotNetKicks.com shout it on DotNetShoutOut

Which IoC container should I use?

Posted by Joe Wilson on Thursday, September 10, 2009 12:07 PM

This came up on the Alt.Net Yahoo Group/mailing list today.  There are tons of tools out there for inversion of control.  They have been compared here and other places online.  Nobody wants their app tied to the Betamax of IoC tools, so people are anxious to pick the best one.

All containers keep a hash table of your interfaces mapped to your concrete classes.  Most will let you request a specific instance with a string token.  Most will let you control instance creation (singleton, etc.).  The popular IoC containers have fluent configuration and use conventions to figure out that IEmailService maps to EmailService.

So which one should you pick?  Go with the one you already know best and/or the one that is easiest for your dev team to configure.  That's because with the Common Service Locator wrapping your IoC get instance calls, the provider becomes a moot point. 

This is an old OO principal - encapsulate the stuff that can change.  Jeremy Miller pointed out the need for a common IoC wrapper to do just this.  Today's hot new open source IoC container could be tomorrow's dormant project.  If you wrap the calls, you can rip out your IoC provider and most of your code stays the same since it's calling the wrapper.

Here's how I'm doing this using Castle Windsor in a Sharp Architecture project.  First, I create a class to wire up my IoC configurations for my app. 

public static class RegisterIoCContainer
{
    public static void AddComponentsTo(IWindsorContainer container)
    {
        AddApplicationConcernsTo(container);
        AddCoreConcernsTo(container);
    }

    private static void AddApplicationConcernsTo(IWindsorContainer container)
    {
        container.Register(Component
            .For<IMappingEngine>
            .Instance(Mapper.Engine)
            .LifeStyle.Singleton);

        container.Register(AllTypes.Pick()
            .FromAssemblyNamed("MyApp.ApplicationServices")
            .WithService.FirstInterface()
            .Configure(c => c.LifeStyle.Transient));
    }

    private static void AddCoreConcernsTo(IWindsorContainer container)
    {
        container.Register(AllTypes.Pick()
            .FromAssemblyNamed("MyApp.Infrastructure")
            .WithService.FirstNonGenericCoreInterface("MyApp.Core")
            .Configure(c => c.LifeStyle.Transient));
    }
}

Note the use of convention-based mappings between assemblies and the different instance lifestyles.  Mapper.Engine has a Singleton lifestyle.  Not that there's anything wrong with that. :>

Next, I create a class to tell Common Service Locator to use Castle Windsor as the provider and to load up those IoC configurations:

    public static class RegisterServiceLocator
    {
        public static void Register()
        {
            var container = new WindsorContainer();

            ServiceLocator.SetLocatorProvider(() => new WindsorServiceLocator(container));

            RegisterIoCContainer.AddComponentsTo(container);
        }
    }

Then I call RegisterServiceLocator.Register() on Application_Start() in the Global.asax.  From then on, I can call the Common Service Locator to get my instance from my interface:

var instance = ServiceLocator.Current.GetInstance<IEmailService>();

I don't often need to use this syntax, since I'm usually pushing external dependencies into a constructor and letting auto-wiring resolve the dependency chain for me.  But I do use this syntax for testing that Common Service Locator is finding the instance I want.

Tags: , ,
Categories: Technical


kick it on DotNetKicks.com shout it on DotNetShoutOut

Image Details