Building SpecificationFor<T>

We had a new developer join our team recently and while going over the codebase, there were a few things that we had built that might not have been obvious as to how we got there. One of them was the way we write and structure our unit tests.

At the time we had started the project, we were following the one test fixture per class convention and have since moved on to a scenario based specification style convention and have introduced a unit test base class that simplifies and increases our development velocity.

The goal of this post is to explain SpecificationFor<T>, our unit test base class, by building it step by step in a way that you can follow on at home.

We’re going to be using a sample class FormatterDecorator and it’s unit test fixture FormatterDecoratorFixture. Our decorator doesn’t do anything special, but should be complex enough to our needs.

FormatterDecorator.cs
public class FormatterDecorator : IFormatter {
  private readonly IFormatter _formatter;
  public FormatterDecorator(IFormatter formatter) {
    _formatter = formatter;
  }

  public string Format(string s) {
    return _formatter.Format(s);
  }
}

And here is the unit test fixture. Note we’re using NUnit for our testing framework and NSubstitute for mocks.

FormatterDecoratorFixture.cs
public class FormatterDecoratorFixture {
  private const string Formatted = "f";
  private const string Unformatted = "p";

  private IFormatter _formatter;
  private FormatDecorator _decorator;

  [SetUp]
  public void SetUp() {
    _formatter = Substitute.For<IFormatter>();
    _formatter.Format(Unformatted).Returns(Formatted);

    _decorator = new FormatterDecorator(_formatter);
  }

  [Test]
  public void FormatShouldReturnFormattedValue() {
    var result = _decorator.Format(Unformatted);
    Assert.That(result, Is.EqualTo(Formatted);
  }
}

The first thing we’re going to change is our convention for one unit test fixture per class. We’re going to move to a scenario based specification style. Fortunately for us, Dave has written a great post on moving to scenario based unit testing. Make sure to read it for the why.

To change to scenario based unit testing, we’re going to rename our test fixture class to match our scenario. For our example, the scenario we’re dealing with formatting, so we’re going to rename our class and filename from FormatterDecoratorFixture to WhenFormatting. If we had any additional scenarios for our class, we would move them into separate scenario based classes and files.

In order to support Resharper’s Navigate To Type feature for moving around our solution, we’re going to group each of the scenarios associated with our class into a FormatterDecoratorFixture outer class. Our new test fixture file should look something like below.

WhenFormatting.cs
public partial class FormatterDecoratorFixture {
  public class WhenFormatting {
    // SetUp and Tests etc
    ....
  }
}

As we’re now working with an individual scenario for each test fixture, it makes sense to move the code that executes the scenario out of the test and into the setup.

  [SetUp]
  public void SetUp() {
    _formatter = Substitute.For();
    _formatter.Format(Unformatted).Returns(Formatted);

    _decorator = new FormatterDecorator(_formatter);
    _result = _decorator.Format(Unformatted);
  }

Now our SetUp method contains the code to initialise and execute our scenario. We can improve the situation by moving these into separate methods. First, we’ve got scenario setup code, our context. Let’s move this into a Context method. Second, we’ve got code that executes our scenario, let’s move this into a Because method.

  [SetUp]
  public void SetUp() {
    Context();
    Because();
  }

  private void Context() {
    _formatter = Substitute.For();
    _formatter.Format(Unformatted).Returns(Formatted);

    _decorator = new FormatterDecorator(_formatter);
  }

  private void Because() {
    _result = _decorator.Format(Unformatted);
  }

Our SetUp method is going to be the same for each scenario, so we can move that into a base class that each test fixture will inherit from. Let’s call this SpecificationFor.

SpecificationFor.cs
public abstract class SpecificationFor {
  [SetUp]
  public void SetUp() {
    Context();
    Because();
  }

  protected virtual void Context() { }
  protected virtual void Because() { }
}

Now a lot of our contexts are going to be creating our subject (or class under test) and it’s dependencies (our substitutes). This is code that is going to be repeated for each scenario associated with a class. For example, if we added a new scenario for our decorator, we would need to duplicate the code that creates our _decorator subject and our _formatter substitute. We could move this code into a base class (i.e. FormatterDecoratorFixtureBase) and have each scenario inherit from that, but instead we’re going to introduce an auto mocker.

As we’re using StructureMap in our code base, it made sense to use the auto mocker built in. Jeremy Miller has a great post explaining the AutoMocker in StructureMap 2.5.

After introducing the auto mocker, our SpecificationFor now looks like this.

public abstract class SpecificationFor<TSubject> {
  private IAutoMocker _autoMocker;

  protected TSubject Subject {
    get { return _autoMocker.ClassUnderTest; }
  }

  [SetUp]
  public void SetUp() {
    _autoMocker = new NSubstituteAutoMocker<TSubject>()

    Context();
    Because();
  }

  protected T Resolve<T>() {
    return _autoMocker.Get<T>();
  }

  ...
}

With our auto mocker in place, our WhenFormatting scenario should be.

WhenFormatting.cs
public partial class FormatterDecoratorFixture {
  public class WhenFormatting
    : SpecificationFor<FormatterDecorator> {
    private const string Formatted = "f";
    private const string Unformatted = "p";

    private string _result;

    public override void Context() {
      Resolve<IFormatter>().Format(Unformatted)
        .Returns(Formatted);
    }

    public override void Because() {
      _result = Subject.Format(Unformatted);
    }

    [Test]
    public void ShouldReturnFormattedValue() {
      Assert.That(_result, Is.EqualTo(Formatted);
    }
  }
}

Improvements that we can make to our SpecificationFor<T> are ensuring that the Subject is created before Because and to lazily initialise Subject to allow us to access it in our Context (should we need to set up the state of our subject or add event subscriptions etc). We can do this by wrapping the subject with a Lazy<T>.

public abstract class SpecificationFor<TSubject> {
  private IAutoMocker _autoMocker;
  private Lazy<T> _lazySubject;

  protected TSubject Subject {
    get { return _lazySubject.Value; }
  }

  [SetUp]
  public void SetUp() {
    _autoMocker = new NSubstituteAutoMocker<TSubject>()
    _lazySubject = new Lazy<T>(() => _autoMocker.ClassUnderTest);

    Context();
    EnsureSubjectIsCreated();
    Because();
  }

  private void EnsureSubjectIsCreated() {
    if (Subject == null) {
      throw new InvalidOperationException();
    }
  }

  ...
}

Using SpecificationFor<T> reduces mundane and repetitive setup code in our unit tests, gives us conventions for naming and placement of code. It’s been a big improvement for our productivity and our tests in general.

Tags: , , ,

2 comments

  1. I see you are using NSubstituteAutoMocker but this is not part of StructureMap itself. Did I miss something or did you just fork StructureMap?

  2. We wrote our own using the AutoMocker<T> class supplied by StructureMap.

    To support NSubstitute, we needed to subclass AutoMocker<T> and implement the ServiceLocator interface.
    The StructureMap source code has support for Rhino Mocks and Moq that we used as a starting point.

Leave a comment