An Evolution of Test-Specification Styles – My Journey to MSpec

Over the last few years, the practice of Test-Driven Design and Behavior-Driven Design has increased in acceptance, even if its practice has not increased in equal proportion.  From my perspective, specification-based design is a natural way to develop software.  Each developer has a preferred framework, and a framework they loathe.  In the .NET world, there are a plethora of unit testing frameworks – NUnit has been nearly ubiquitous; mbUnit was evolutionary; xUnit was revolutionary; MSTest is…er, getting an update.  For BDD, you can find frameworks like SpecUnit.NET, NBehave, and MSpec.  My current framework of choice is MSpec, especially when coupled with StructureMap’s automocking container and a couple helper classes.

From my unscientific observation, developers either love or hate MSpec.  For those that hate MSpec, I wonder if it is the grammatical syntax or the lambda-expression style creating the aversion.  Some even expound MSpec as cryptic and cumbersome.  This seems to be a common complaint – one I hope to address in this post.

I find that those drawn to MSpec have experienced an evolution of testing/specification styles, influenced partially by the community and partially by frameworks they have used.  At the very least, this has been my experience as I have transitioned from xUnit frameworks.

Conventions of MSpec

I particularly like the conventions MSpec encourages using its four delegate types:

Establish:

  • Provides setup (context) for the specification
  • One per class (but not required)
  • “Unlimited” per specification or inheritance chain
  • Runs down the inheritance chain prior to the Because delegate

Because:

  • The action/event being tested
  • One per specification

It:

  • An assertion (usually extension methods/fluent interfaces based on NUnit/xUnit Assert classes)
  • “Unlimited” per specification/class
  • Can be “hosted” in a Behavior class
  • Runs after the Because
  • Can be reused when placed in a Behavior class
  • If body of delegate is missing, will mark as “Ignored” or “Not Implemented” in a test runner

Cleanup:

  • Provides teardown for the specification
  • One per class (but not required)
  • “Unlimited” per specification or inheritance chain
  • Runs up the inheritance chain after the It delegates are completed

MSpec also has one other delegate type (Behaves_like<T>) and several optional attributes available (Subject, Tag, Ignore, Behavior).  [Subject] provides additional information about the specification. [Tag] is similar to the [Category] attribute in NUnit.  [Ignore] is self-explanatory. [Behavior] marks a class made up entirely of assertions (It delegates).  Behaves_like<T> is a delegate type that can be included in a specification block taking the place of a set of assertions (It delegates).

 

NUnit – TestFixture-Per-Class

I have gone from using a TestFixture-Per-Class style to a behavior-driven/context-specification style.  I would like to use the standard HomeController, created in an ASP.NET MVC 1.0 project, as an example class to explore this evolution. 

In my TestFixture-Per-Class days, I may have tested the Index action as follows:

[TestFixture]
public class HomeControllerTests
{
    [Test]
    public void IndexActionTest()
    {
        var controller = new HomeController();
        var result = (ViewResult) controller.Index();
        Assert.AreEqual("Welcome to ASP.NET MVC!", result.ViewData["Message"]);
    }
}

I do like the simplicity of the code.  One line to set up the test, one to execute, and one to assert.  There is a little ceremony involved with marking the class and methods with the NUnit attributes.  With this simple test, it is easy to distinguish the setup code from the assertion; yet, a more complex test would make scanning the test more difficult.  Comments can help, but tend to just add noise.

 

NUnit – Arrange/Act/Assert

With the advent of BDD, I started naming my classes and expectations as inspired by BDD syntax.  I might have used the [SetUp] attribute or a base class to organize my test code in a style similar to the following:

[TestFixture]
public class when_I_go_to_the_home_page: AAA
{
    private HomeController _controller;
    private ViewResult _result;

    protected override void Arrange()
    {
        _controller = new HomeController();
    }
    protected override void Act()
    {
        _result = (ViewResult)_controller.Index();
    }

    [Test]
    public void then_the_welcome_message_should_be_displayed()
    {
        _result.ViewData["Message"].ShouldEqual("Welcome to ASP.NET MVC!");
    }
}

This actively separates out the different responsibilities of the test.  You can see where the setup code is, as well as the action being tested.  The assertion is the only line of code in the test method.  There is still ceremony involved with the attributes.  Plus, we have added a little more ceremony and noise with the Arrange() and Act() overrides.  This simple test does not necessarily need the parts split in this manner, but it would help with more complex scenarios.  Additionally, the assertion is using extension methods based on the NUnit Assert classes which provides a little more clarity to the assertion.

 

MSpec

Once started down the path of a behavior-driven (or context/specification) style, I started looking at frameworks devoted to that style.  MSpec is one of those frameworks.  Here is the Index action specification in MSpec:

public class when_I_go_to_the_home_page
{   
    Establish context = () =>  _controller = new HomeController();
    Because of = () => _result = (ViewResult)_controller.Index(); 
    It should_display_the_welcome_message = () => _result.ViewData["Message"].ShouldEqual("Welcome to ASP.NET MVC!"); 
    
    static HomeController _controller;
    static ViewResult _result;
}

If you look closely, this specification is very similar to the first NUnit test.  However, there are no attributes to specify and the specification has a distinct functional separation.  The Establish/Because/It syntax is analogous to the Given/When/Then language used in user stories or Arrange/Act/Assert syntaxes used in the previous example.  In my opinion, this has less noise than the test using NUnit with an AAA base class – even while using the lambda delegate syntax.

 

MSpec – SpecificationFor<ClassUnderTest>

I often use a base class to handle some of my setup code. Using StructureMap and RhinoMocks, it generates and injects proxied dependencies for the given class.  In this example, I have no dependencies to wire up, but I think you can still see the benefits.

public class when_I_go_to_the_home_page : SpecificationFor<HomeController>
{
    Because of = () => _result = (ViewResult)ClassUnderTest.Index(); 
    It should_display_the_welcome_message = () => _result.ViewData["Message"].ShouldEqual("Welcome to ASP.NET MVC!"); 
    
    static ViewResult _result;
}

The Establish delegate is not needed in this specification, because I have wired up the class via the base class.  I feel this version is most clear and concise of all the examples, and neither cryptic nor cumbersome  If you are interested in the SpecificationFor<T> base class and the supporting components, check out my previous post

 

Looking to the Future

I hope that this post has shown that MSpec does not have to be cryptic, nor cumbersome.  If you considered it as such before, please take another critical look.

Given the evolving state of the craft, I am sure that my test/specification style will continue to gradually change.  I am sure that my framework of choice will eventually change as well, especially as each framework is extended and challenged by others.  Hopefully, you can be open to evolving your style as well.

14 thoughts on “An Evolution of Test-Specification Styles – My Journey to MSpec”

Comments are closed.