AutoMockingContainer: Now on Silverlight 4.0

The #Fellows AutoMockingContainer (AMC) which I recently introduced, is now available on Silverlight 4.0.  There have been no code changes, but the the assemblies have been compiled against the SL 4 assemblies and Rhino Mocks 3.5 for Silverlight.  Get the binaries from the link below and source code from the Bitbucket repo.

SharpFellows.AutoMockingContainer.Silverlight.dll (13.50 kb)

June 24 2010

A new AutoMockingContainer (which can work with MEF)

About auto-mocking

The Problem of Dependencies

When working in an Inversion of Control (IOC) container, best practice dictates that you let the IOC do as much work for you as possible and inject your dependencies.  As a rule of thumb, this typically means that classes contain less code and conform better to the Single Responsibility Principle, but they do usually end up with a greater number of dependencies. 

In addition to this. IOC-style coding often uses constructor injection for dependencies which are critical to the functioning of the class and property injection (aka setter injection) for other dependencies (see Martin Fowler for explanation of these terms).

The net result of all this, is that classes often end up with quite a few constructor parameters.  And then when you come to write some unit tests for your classes, you end up having to create and manage a large number of mock objects, even though not all of those may be relevant to your test.

The Solution: Automatically Creating Mocks

And one day some developer decided that this drudge work of creating and managing mock objects could be automated.  In fact, the guys at Eleutian were the first ones to come up with an Auto-Mocking Container (AMC) on the .Net platform … they did it by adding a facility to Castle Windsor.  Since then, AMCs have been added to StructureMap and, more recently, James Broome has produced an AMC for use with Machine.Specifications.  These are great libraries and work well.

And do we need another AMC?

With the notable exception of James’s library, you typically need to take a dependency on an IOC and spin it up in your unit tests.  This is not too much of a problem if your IOC has some support for an AMC.  On my project we are using MEF as an IOC and there isn’t (before now) an AMC that works with that.

The reason I didn’t use James Broome’s library is that Machine.Specifications (aka MSpec) is not really my cup of tea.  I was imprinted with a different BDD framework, NBehave.  James’s library is quite tightly coupled to the MSpec way of working.

Introducing the SharpFellows.AutoMockingContainer

It’s probably best to introduce the #Fellows AMC through some code:

public class BlogViewModel
{
    private IAuthorRepository _authors;
    private ISpamScoringService _spamScoring;

    public BlogViewModel(IAuthorRepository authors, ISpamScoringService spamScoring)
    {
        _authors = authors;
        _spamScoring = spamScoring;
    }

    public void RecordComment(string author, string comment)
    {
        // Do something interesting here
    }
}

[TestClass]
public class BlogViewModelTests
{
    [TestMethod]
    public void TestMethod1()
    {
        // ARRANGE
        var container = new ObjectFactory();
        var viewModel = container.CreateObject<BlogViewModel>();
        var authorName = "author.name";
        var comment = "great stuff";

        // ACT
        viewModel.RecordComment(authorName, comment);

        // ASSERT
        container.GetDependency<IAuthorRepository>()
                 .AssertWasCalled(repo => repo.FindByName(authorName));
        container.GetDependency<ISpamScoringService>()
                 .AssertWasCalled(scoring => scoring.MeasureSpamScore(authorName, comment));
    }
}

As you can see, ObjectFactory is where the good stuff happens.

MEF Support

The #Fellows AMC provides support for MEF, but it is not a required dependency.  The project files do have a reference to System.ComponentModel.Composition (the MEF assembly) but unless you actually invoke the MEF Dependency Locator through policy, it will never be required at run-time.

And here is a MEF-based view-model with a test using the #Fellows AMC:

public class MefBlogViewModel
{
    private IAuthorRepository _authors;

    [ImportingConstructor]
    public MefBlogViewModel(IAuthorRepository authors)
    {
        _authors = authors;
    }

    [Import]
    public ISpamScoringService SpamScoring { get; set; }

    public void RecordComment(string author, string comment)
    {
        // Do something interesting here
    }
}

[TestClass]
public class MefBlogViewModelTests
{
    [TestMethod]
    public void TestMethod1()
    {
        // ARRANGE
        var container = new ObjectFactory();
        container.Policy.Set(new MefDependencyLocator());
        var viewModel = container.CreateObject<BlogViewModel>();
        var authorName = "author.name";
        var comment = "great stuff";

        // ACT
        viewModel.RecordComment(authorName, comment);

        // ASSERT
        container.GetDependency<IAuthorRepository>()
                 .AssertWasCalled(repo => repo.FindByName(authorName));
        container.GetDependency<ISpamScoringService>()
                 .AssertWasCalled(scoring => scoring.MeasureSpamScore(authorName, comment));
    }
}

The #Fellows AMC will inject against an [ImportingConstructor] (or will invoke a default parameter-less constructor) and will then inject against properties attributed with [Import].  Constructor parameters or properties attributed [ImportMany] are not currently supported for auto mock injection.

Now it takes quite a sharp eye to spot the difference in the test.  It is a single line of code that sets up MEF as part of the policy:

container.Policy.Set(new MefDependencyLocator());

What is Policy and how is it applied?

AutoMocking Policy is really what gives the #Fellows AMC its flexibility and is what sets it apart from the other AutoMocking Containers which are out there.  Put simply, policy consists of three areas:

AMC.Policy

Each of these areas be configured on an individual container (as per the above), or it can be configured at a static level where it will affect all containers in the AppDomain that are subsequently created.

ObjectFactory.DefaultPolicy.Set(new MefDependencyLocator());

Policy components that are currently available in #Fellows AMC are as follows:

Dependency Locators
  • Reflection-based (using the greediest constructor)     [default]
  • MEF-based
Lifecycle Controllers
  • Shared dependencies [default]
  • Non-shared dependencies
Mock Generators
  • Rhino Mocks

 

The three areas of policy work together to give the #Fellows AMC its overall behaviour.

Policy is an area that I think can be developed a lot further, both in terms of adding new policy components as well as allowing policy to be specified at a more granular level.  For instance:

  • specifying a mock generator that will instantiate object for classes in a given namespace
  • specifying that some classes should not have auto-mocking applied at all
  • specifying that certain dependencies should be shared whilst others should not

Furthermore, I suspect it would extremely useful to allow policy to be read from the config file.  This would allow us to centrally specify policy for all our tests without needing some code to adjust static state on the ObjectFactory.

Roadmap for the #Fellows AutoMockingContainer

The first thing I want to do is to get Silverlight support.  Or more specifically, an assembly which is compiled for Silverlight and against the relevant Silverlight assemblies (e.g. RhinoMocks SL version), since that is all that’s needed.  And after that, I’m hoping to extend the policy mechanism significantly.

Where can I get the #Fellows AutoMockingContainer?

Assemblies for .Net 4.0 are attached to this blog post.  If you are interested in the source code, then you can download it from the BitBucket repository.

SharpFellows.AutoMockingContainer.dll (13.00 kb)

June 15 2010
Older Posts