MSpec is Fantastic!


Update: this blog is no longer active. For new posts and RSS subscriptions, please go to http://saintgimp.org.

I’ve previously written about the Behavior-Driven Development style of TDD and about how to use such a style in MSTest.  I’ve done this on several personal and business projects and it’s worked pretty well, but I recently got around to trying Aaron Jensen’s MSpec and I have to say there’s no going back.  Conceptually my tests are the same but mechanically MSpec just flows so much better.

Here’s test context from a personal game project of mine written in my old MSTest BDD framework:

[TestClass]

public class when_the_planet_is_initialized : PlanetContext

{

    protected override void Context()

    {

        base.Context();

    }

 

    protected override void BecauseOf()

    {

        _planet.Initialize(_location, _radius);

    }

 

    [TestMethod]

    public void should_initialize_the_renderer()

    {

        _planetRenderer.AssertWasCalled(x => x.Initialize(_radius));

    }

 

    [TestMethod]

    public void should_create_terrain()

    {

        _terrainFactory.AssertWasCalled(x => x.Create(_radius));

    }

}

It works, but it’s noisy.

  • Each spec requires a minimum of four text lines.
  • There’s a lot of type and access control gook that obscures the intent.
  • Even though there’s no test-specific context to set up, I still have a Context method that simply calls the base class. Strictly speaking this isn’t required, but I’ve found that if I leave it out and then decide to add it later, I often forget to call base.Context so I always leave this boilerplate code here as a reminder.  Call it a defensive habit.

Now here’s the same context re-written in MSpec:

[Subject(typeof(Planet))]

public class when_the_planet_is_initialized : PlanetContext

{

    Because of = () =>

        _planet.Initialize(_location, _radius);

 

    It should_initialize_the_renderer = () =>

        _planetRenderer.AssertWasCalled(x => x.Initialize(_radius));

 

    It should_create_terrain = () =>

        _terrainFactory.AssertWasCalled(x => x.Create(_radius));

}

The MSTest version requires 25 text lines, the MSpec version 12 text lines.  This context doesn’t require an “Establish context” delegate, but if I wanted to add one later the form is the same as the other clauses and I don’t have to remember to call a base class version.  There’s far less compiler gook getting in the way and the code reads very easily.  It just oozes elegance.  Ok, I suppose Rubyists or Pythonistas might still call this noisy but for C# it’s amazing.  It can be daunting at first when your brain exclaims, “That can’t possibly be legal C# code!” but once you figure out that it’s just lambda expressions assigned to delegate fields it all makes perfect sense.

MSpec also includes BDD specification extension methods very similar to the ones I wrote about so you don’t have to worry about writing and maintaining that code, either.

If you’re at all interested in BDD, you owe it to yourself to try MSpec!

Comments (4)

  1. Jonathan says:

    We started using MSpec a little while ago and we agree–there’s no going back.

    For us, it’s about having our tests truly become documentation for what the code is doing.  Traditional xUnit didn’t have that.  With MSpec we concentrate on what the spec should be named (the it "should…" part).  That helps us clarify the intent of our code before we even write the test.  Once we know what the spec should be asserting, writing the production code is easier.

  2. Kyle Bailey says:

    How did you get MSpec setup and running?

  3. Eric Lee says:

    Kyle, there’s a page with lots of good links for MSpec at http://www.awkwardcoder.com/index.php/2010/04/13/how-to-mspec/.  Several of those links are to tutorials that will help you get started.

    Is there a specifc question you have?  General setup is pretty easy.  Grab the latest MSpec build, put it on your local drive, run the test runner install batch file (if you’re using Resharper or TD.Net), and add a reference in your unit test project.  That’s it.

    The last time I looked, the Resharper runner install batch file didn’t correctly install things for Resharper on VS2010.  That may nor may not be fixed in the latest MSpec build yet, but if it’s not, you should be able to open up the install batch file and pretty quickly reason out how to change it for VS2010 (the version number for 2010 is 10.0).

  4. Kyle Bailey says:

    I was able to get it running after a bunch of reading. I think I really just had a problem getting testdriven working with it.

    Thanks for the link btw that was also helpful.