About the author

Steven Harmansteven harman :: makes sweet software with computers!

For recent posts and more about me, scroll to the bottom.

Subscribe

  • Subscribe to my feed. via RSS
  • Subscribe via email via email

News

Badges

  • Subtext Project
  • Support Subtext

Toward a Better Use of Context/Specification

If you’ve hand-rolled your own Context/Specification apparatus to support your test spec-first lifestyle, you’ve likely got a base class that looks something like the following:

   1:  public abstract class concerns
   2:  {
   3:    [SetUp]
   4:    public virtual void setup_context()
   5:    {
   6:      context();
   7:    }
   8:   
   9:    protected virtual void context() {}
  10:   
  11:    protected virtual void decontext() {}
  12:   
  13:    [TearDown]
  14:    public virtual void cleanup_context()
  15:    {
  16:      decontext();
  17:    }
  18:  }

The above is basically co-opting an existing unit testing tool into something more language-oriented and behavior focused. In this case we’ve built upon MbUnit, adding a couple of hook methods that are responsible for

  1. setting up the context before an individual specification - context
  2. optionally doing any necessary teardown after each specification – decontext

An example

Using this base class, we’ll end up with specs that might looks something like

   1:  using Skynet.Core
   2:   
   3:  public class when_initializing_core_module : concerns
   4:  {
   5:    SkynetCoreModule _core;
   6:    
   7:    public void context()
   8:    {
   9:      //we'll stub it...you know...just in case
  10:      var skynetController = stub<ISkynetMasterController>();
  11:      _core = new SkynetCoreModule(skynetController);
  12:      _core.Initialize();
  13:    }
  14:    
  15:    [Specification]
  16:    public void it_should_not_become_self_aware()
  17:    {
  18:      _core.should_not_have_received_the_call(x => x.InitializeAutonomousExecutionMode());
  19:    }
  20:    
  21:    [Specification]
  22:    public void it_should_default_to_human_friendly_mode()
  23:    {
  24:      _core.AssessHumans().should_equal(RelationshipTypes.Friendly);
  25:    }
  26:    
  27:    // more specifications under this same context
  28:    // ...
  29:  }

Here we’ve set up a common context that holds true for each of specifications that follow it. This is also a common pattern used in classic unit testing and in fixture-per-class style Test-Driven Development. In fact, the only real between the above and what I’d have done in fixture-per-class style TDD is the_use_of_underscores, intention revealing names, and the context hook method.

Is that really any different?

These modest cosmetics are not what differentiate Context/Specification from other styles of test-first development. For me, the core differentiator is the realization that there are often many contexts under which a particular behavior my be exercised, each producing an observable and possibly different set of results.

More directly, with Context/Specification we’ll often have many fixtures per class/feature/functional area of the code base. Doing this allows us to keep the context as simple as possible and focused on the behavior being specified. I’ve found that I tend toward having a single file-per-class/functional area, with any number of contexts (fixtures) in each file.

Another big change is that specifications should be side effect free. To be more exact, the specification is actually an observation about the interactions that occurred while or the state of the system after some behavior has been exercised.

Make it explicit!

We want small, focused contexts, yes? And we want side effect free specifications too, yeah? So why not leverage our tools to help guide us in that direction? YES!

Consider the following tweak to the concerns base class

   1:  public abstract class concerns
   2:  {
   3:    [FixtureSetUp]
   4:    public virtual void setup_context()
   5:    {
   6:      context();
   7:    }
   8:   
   9:    protected virtual void context() {}
  10:   
  11:    protected virtual void decontext() {}
  12:   
  13:    [FixtureTearDown]
  14:    public virtual void cleanup_context()
  15:    {
  16:      decontext();
  17:    }
  18:  }

Such a base class will only set up each context once, no matter how many specifications are made against the context. This does a couple of things for us

  • requires side effect free specifications
  • guides us toward smaller, more focused contexts
  • might actually make our specs run faster!

As for the running faster bit, that is not guaranteed as it really depends on how you were writing your specs before making this change.

Some things to watch for

If, however, you were following more of a fixture-per-class style, you might find a drastic reduction in how long it takes your spec suite to run. The corollary is, of course, that you likely don’t have small contexts. That is trouble and is often an indicator that the one, large context is itching to be split out into two or more discrete contexts.

Upon switching your base class over to this more rigid Context/Specification pattern, you might also find that you have some – or many – broken specs. This is an indicator that those broken specs were not side effect free. Well, actually its suggesting that some of the sibling specs weren’t side effect free and they are now causing other specs to break.

Notes:

The portions of this article relating to changing from a standard context set up to a once-per-fixture style apply to most of the hand-rolled Context/Specification base classes I’ve seen in the wild.

If, however, you are using a tool like MSpec, then you’re in good shape as Aaron applied this same philosophy out of the gate. And if you’re not using MSpec, I’d encourage you to take a look at it for inspiration, if nothing else.

kick it on DotNetKicks.com

What others are saying.

# re: Toward a Better Use of Context/Specification
Gravatar Scott
May 27, 2009
A bit confusing (nice to see the skynet thing come back though). The spec you show doesn't really make your argument. The key difference in your illustration is Fixture setup instead of SetUp (which is key, as SetUp is all but barred from our specs) and I think the spec shown is just noise.

Not to harsh too much, but I think your point, a valid and good one, is lost in translation.
# re: Toward a Better Use of Context/Specification
Gravatar Steven Harman
May 27, 2009
@scott,
Good points. @laribee mentioned that another bit of example code, illustrating a specification with side-effects may be helpful as well. What do you think? Care to help me craft such an example?
# re: Toward a Better Use of Context/Specification
Gravatar Tim
May 29, 2009
We started using nBehave a bit more, and I this is how they set up their contexts when you inherit from SpecBase. You may not have to roll your own...though I still prefer the "old way" at this point, and your hand rolled Specification.cs is still getting used. ;)
Comments have been closed on this topic.