Blog

AutoMocking Container

January 13, 2008

When writing unit tests that involve interaction based testing, you most likely end up using one of the mocking frameworks out there. The mocking framework I'm using is Rhino Mocks. For an explanation of the differences between state based testing and interaction based testing, you can have a look at the excellent Mocks aren't Stubs from Martin Fowler. For a nice introduction on Rhino Mocks, have a look at this screen cast.

Anyway, when writing interaction based unit tests for the following code

public class CustomerService
{
    private ICustomerRepository _customerRepository;
    private IActiveDirectoryGateway _activeDirectory;

    public CustomerService(
        ICustomerRepository customerRepository,
        IActiveDirectoryGateway activeDirectory)
    {
        _customerRepository = customerRepository;
        _activeDirectoryGateway = activeDirectory;
    }

    public void CreateCustomer(Customer customer)
    {
        Boolean succeeded = 
            _customerRepository.Save(customer); 
        if(succeeded)
        {
            _activeDirectory.GrantAccessTo(customer);     
        }
    }
}

you probably end up writing unit tests like this:

[TestFixture]
public class ClassicCustomerServiceTestFixture
{
    private MockRepository _mockRepository;
    private ICustomerRepository _customerRepository;
    private IActiveDirectoryGateway _activeDirectoryGateway;
    private CustomerService _customerService;

    [SetUp]
    public void SetUp()
    {
        _mockRepository = new MockRepository();
        _customerRepository = _mockRepository
            .DynamicMock<ICustomerRepository>();
        _activeDirectoryGateway = _mockRepository
            .DynamicMock<IActiveDirectoryGateway>();
        _customerService = 
            new CustomerService(_customerRepository, 
                                _activeDirectoryGateway);
    }

    [TearDown]
    public void TearDown()
    {
        _customerService = null;
        _activeDirectoryGateway = null;
        _customerRepository = null;
        _mockRepository = null;
    }
    
    [Test]
    public void VerifyInteractionWithCustomerRepository()
    {
        Customer customer = new Customer();
        using(_mockRepository.Record())
        {
            Expect.Call(_customerRepository.Save(customer))
                .Return(false)
                .Message("Expected Save to be called once.");
        }
            
        using(_mockRepository.Playback())
        {
            _customerService.CreateCustomer(customer);    
        }
    }

    [Test]
    public void VerifyInteractionWithActiveDirectoryGateway()
    {
        Customer customer = CreateCustomer();
        using(_mockRepository.Record())
        {
            SetupResult.For(_customerRepository.Save(null))
                .IgnoreArguments()
                .Return(true);
            _activeDirectoryGateway.GrantAccessTo(customer);
            LastCall.Message("Expected GrantAccessTo to be 
                              called once.");    
        }
            
        using(_mockRepository.Playback())
        {
           _customerService.CreateCustomer(customer);        
        }
    }

    private static Customer CreateCustomer()
    {
        return new Customer();
    }
}

As you can see, there is a lot of code in the SetUp method that creates mock objects for the dependencies that are required by the subject under test ( = the CustomerService class). Besides the fact that you need to type it over and over again for every test fixture, the major disadvantage with this approach is that the unit tests are not self-containing. Reading and understanding the unit tests involves reading both the test case methods and the SetUp/TearDown methods.

The approach I've been using for the last couple of months is the AutoMocking container from Jacob Lewallen. Lets speak code shall we.

[TestFixture]
public class CustomerServiceTestFixture : 
    AutoMockingTestFixture<CustomerService>
{
    [Test]
    public void VerifyInteractionWithCustomerRepository()
    {
        Customer customer = new Customer();
        using(MockRepository.Record())
        {
            Expect.Call(
                MockCustomerRepository.Save(customer))
                .Return(false)
                .Message("Expected Save to be called once.");
        }
            
        using(MockRepository.Playback())
        {
            CreateSubject().CreateCustomer(customer);    
        }
    }

    [Test]
    public void VerifyInteractionWithActiveDirectoryGateway()
    {
        Customer customer = CreateCustomer();
        using(MockRepository.Record())
        {
            SetupResult.For(
                MockCustomerRepository.Save(null))
                .IgnoreArguments()
                .Return(true);
            MockActiveDirectoryGateway.
                GrantAccessTo(customer);
            LastCall.Message("Expected GrantAccessTo to be 
                              called once.");    
        }
            
        using(MockRepository.Playback())
        {
            CreateSubject().CreateCustomer(customer);        
        }
    }

    private ICustomerRepository MockCustomerRepository
    {
        get { return Mock<ICustomerRepository>(); }
    }
        
    private IActiveDirectoryGateway 
        MockActiveDirectoryGateway
    {
        get { return Mock<IActiveDirectoryGateway>(); }
    }

    private static Customer CreateCustomer()
    {
        return new Customer();
    }
}

Notice how the SetUp/TearDown methods are completely gone. I've created this base class test fixture, called AutoMockingTestFixture that encapsulates the use of the AutoMocking container, like so:

public abstract class AutoMockingTestFixture<TSubject>
{
    private AutoMockingContainer _autoMockingContainer;

    protected AutoMockingContainer AutoMockingContainer
    {
        get { return _autoMockingContainer; }
    }
        
    protected MockRepository MockRepository
    {
        get { return _autoMockingContainer.MockRepository; }
    }
        
    protected T CreateSubject()
    {
        return _autoMockingContainer.Create<TSubject>();
    }
        
    protected T Mock<T>() where T : class
    {
        return _autoMockingContainer.Get<T>();
    }

    protected T Stub<T>() where T : class
    {
        _autoMockingContainer.Mark<T>().Stubbed();
        return _autoMockingContainer.Get<T>();   
    }
        
    protected virtual void SetUp()
    {}

    protected virtual void TearDown()
    {}
        
    [SetUp]
    public void BaseSetUp()
    {
        _autoMockingContainer = 
            new AutoMockingContainer(new MockRepository());
        _autoMockingContainer.Initialize();
        SetUp();
        CreateSubject();
    }

    [TearDown]
    public void BaseTearDown()
    {
        TearDown();
        _autoMockingContainer = null;
    }
}

Using this base test fixture ensures that all interaction based unit tests in the derived test fixture are completely self-containing. Everything you need to know about a particular unit test is right there in the same method. Another big advantage is the fact that you can now add dependencies to the constructor of the CustomerService class without breaking any tests whatsoever.

If you're interested in using this approach, the code for the AutoMocking container can be downloaded from Ayende's Subversion repository (see rhino-testing). Under the hood, the AutoMocking container leverages Castle Windsor for doing its magic.

Profile picture of Jan Van Ryswyck

Jan Van Ryswyck

Thank you for visiting my blog. I’m a professional software developer since Y2K. A blogger since Y2K+5. Curator of the Awesome Talks list. Past organizer of the European Virtual ALT.NET meetings. Thinking and learning about all kinds of technologies since forever.

Comments

About

Thank you for visiting my website. I’m a professional software developer since Y2K. A blogger since Y2K+5. Curator of the Awesome Talks list. Past organizer of the European Virtual ALT.NET meetings. Thinking and learning about all kinds of technologies since forever.

Contact information

(+32) 496 38 00 82

infonull@nullprincipal-itnull.be