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

Category:UncategorizedTag: , , , :

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

  1. I’m not an MSpec fan either. But I have a different reason: I don’t like writing tests using a coding style that I would not use the rest of my code.

    If we look at your final class:

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

    You are declaring public fields, but you are not declaring them as public. That would not last a code review for me. It might read easier, but now you are setting a bad president for your non-test code.

    Next is the use of statics. I work hard to rid them from my code, expecially static fields. They don’t belong in my production code, then they don’t belong in my test code.

    Basically, MSpec is creating an alternative C# land by trying too hard to create a fluent interface using class declarations, which come off a bit oddly.

    In other word: I’m turning into an old man, now GET OFF MY LAWN! — and use C# like it was meant to be used.

  2. Nice rebuttal, Chris! My turn…

    I don’t have public fields in this code. If you do not mark the class visibility – it is private.

    As for the statics, it did bother me when I was first investigating the framework – but it bothers me less now. I try to keep static fields out my production code as well. But each problem has its own solution and static delegates seem to create a viable solution. Statics are good solutions in other instances as well. For example, object mothers are sometimes static, and other times are code-generated. I have static members in my in-memory repositories. I use the solution that makes sense in its context.

    As for the alternative C# land…MSpec is using delegates via lambda syntax in a conventional manner. Once again, doesn’t bother me… especially when I feel I can write and debug my test code faster. I can understand your aversion – I just don’t have the same perspective.

    And remember, when you are working in my project, its my lawn. 😛 If you want me to use NUnit on your lawn, old man, I will.

    (One last note – the SpecificationFor classes are independent of MSpec and can be used with any framework.)

    See you tomorrow!

  3. Richard,
    Thanks for the summary of what the delegates are doing. I use MSpec for a while now and it was hard to find out how to use it… Now it will be a little bit easier…

  4. I really like your SpecificationsFor style base class, and so I tried out a similar approach. It works for most of my specs, but I have a few which use Behaviors, and I keep getting failures because it tells me the SUT is null. I’m guessing MSpec is failing to wire up the SUT in the behaviors with the generic one in my base class. Did you run into this problem, and were you able to overcome it?

  5. First off… Richard, thank you so much providing an example that shows me just how MSpec and xUnit type code differs. That is a very good easy to understand example, and really helped me to understand what MSpec is trying to do.

    I’m still not sure though. I can see both points. When I see the MSpec code, I think about it being an internal DSL for doing the testing, and I start to think that perhaps it should just go ahead and be it’s own language instead of trying to live inside of C#. On the other hand, I wonder about the value of using another language to unit test C# code, so I can see Chris’s point there.

  6. @Richard Cirerol
    Richard, it seems to have magically fixed itself. I had another task to address, and when I came back to this it was somehow working. Gotta love that. Thanks for the article!

  7. @John Sonmez, Glad to hear this post helped you out.

    I think that you are spot-on when you call MSpec an internal DSL. Chris Brandsma and I had a similar conversation yesterday morning.

    Look for another post soon on this topic. (Thanks for the inspiration!)

  8. This is awesome. Very clear step by step of thinking to use mspec. I has been use mspec for my work (TDD.NET cc.net) . It just worked.

    Thank you for this kind of article.

Comments are closed.

Find me

RSS
Facebook
Twitter
LinkedIn

Disclaimer

The opinions and content expressed here are my own and not those of my employer.