Behaviours in MSpec

MSpec is awesome, I think it’s praised by myself and others enough for that particular point to not need any expansion; however, there is a particular feature I would like to highlight that hasn’t really got a lot of press: behaviours.

Behaviours define reusable specs that encapsulate a particular set of, you guessed it, behaviours; you’re then able to include these specs in any context that exhibits a particular behaviour.

Lets go with the cliche’d Vehicle example. Given an IVehicle interface, with Car and Motorbike implementations; these all expose a StartEngine method and some properties reflecting the state of the vehicle. We’ll start the engine and verify that it is actually started, whether it’s got anything on the rev counter, and whether it’s killing our planet in the process (zing!).

public interface IVehicle
{
  void StartEngine();
  bool IsEngineRunning { get; }
  bool IsPolluting { get; }
  int RevCount { get; }
}

public class Car : IVehicle
{
  public bool IsEngineRunning { get; private set; }
  
  public void StartEngine()
  {
    // use your imagination...
  }
}

public class Motorbike : IVehicle
{
  public bool IsEngineRunning { get; private set; }

  public void StartEngine()
  {
    // use your imagination...
  }
}

Those are our classes, if rather contrived, but they’ll do. Now what we need to do is write some specs for them.

public class when_a_car_is_started
{
  Establish context = () =>
    vehicle = new Car();
  
  Because of = () =>
    vehicle.StartEngine();
  
  It should_have_a_running_engine = () =>
    vehicle.IsEngineRunning.ShouldBeTrue();
  
  It should_be_polluting_the_atmosphere = () =>
    vehicle.IsPolluting.ShouldBeTrue();
  
  It should_be_idling = () =>
    vehicle.RevCount.ShouldBeBetween(0, 1000);
  
  static Car vehicle;
}

public class when_a_motorbike_is_started
{
  Establish context = () =>
    vehicle = new Motorbike();
  
  Because of = () =>
    vehicle.StartEngine();
  
  It should_have_a_running_engine = () =>
    vehicle.IsEngineRunning.ShouldBeTrue();

  It should_have_a_running_engine = () =>
    vehicle.IsEngineRunning.ShouldBeTrue();

  It should_be_polluting_the_atmosphere = () =>
    vehicle.IsPolluting.ShouldBeTrue();

  It should_be_idling = () =>
    vehicle.RevCount.ShouldBeBetween(0, 1000);
  
  static Motorbike vehicle;
}

Those are our specs, there’s not much in there but already you can see that we’ve got duplication. Our two contexts contain identical specs, they’re the same in what they’re verifying, the only difference is the vehicle instance. This is where behaviours can come in handy.

With behaviours we can extract the specs and make them reusable. Lets do that.

Create a class for your behaviour and adorn it with the Behaviors attribute — this ensures MSpec recognises your class as a behaviour definition and not just any old class — then move your specs into it.

[Behaviors]
public class VehicleThatHasBeenStartedBehaviors
{
  protected static IVehicle vehicle;
  
  It should_have_a_running_engine = () =>
    vehicle.IsEngineRunning.ShouldBeTrue();

  It should_have_a_running_engine = () =>
    vehicle.IsEngineRunning.ShouldBeTrue();

  It should_be_polluting_the_atmosphere = () =>
    vehicle.IsPolluting.ShouldBeTrue();

  It should_be_idling = () =>
    vehicle.RevCount.ShouldBeBetween(0, 1000);
}

We’ve now got our specs in the behaviour, and have defined a field for the vehicle instance itself (it won’t compile otherwise). This is our behaviour complete, it defines a set of specifications that verify that a particular behaviour.

Lets hook that behaviour into our contexts from before:

public class when_a_car_is_started
{
  Establish context = () =>
    vehicle = new Car();
  
  Because of = () =>
    vehicle.StartEngine();
  
  Behaves_like<VehicleThatHasBeenStartedBehaviors> a_started_vehicle;
  
  protected static Car vehicle;
}

public class when_a_motorbike_is_started
{
  Establish context = () =>
    vehicle = new Motorbike();
  
  Because of = () =>
    vehicle.StartEngine();
  
  Behaves_like<VehicleThatHasBeenStartedBehaviors> a_started_vehicle;
  
  protected static Motorbike vehicle;
}

We’ve now put to use the Behaves_like feature, which references our behaviour class and imports the specs into the current context. Now when you run your specs, the specs from our behaviour are imported and run in each context. We don’t need to assign anything to that field, just defining it is enough; the name you choose for the field is what’s used by MSpec as the description for what your class is behaving like. In our case this is translated roughly to “when a motorbike is started it behaves like a started vehicle”.

There are a couple of things you need to be aware of to get this to work: your fields must be protected, both in the behaviour and the contexts; and the fields must have identical names. If you don’t get these two correct your behaviour won’t be hooked up properly. It’s also good to know that the fields do not need to have the same type, as long as the value from your context is assignable to the field in the behaviour then you’re good; this is key to defining reusable specs for classes that share a sub-set of functionality.

In short, behaviours are an excellent way of creating reusable specs for shared functionality, without the need to create complex inheritance structures. It’s not a feature you should use lightly, as it can greatly reduce the readability of your specs, but it is a good feature if you’ve got a budding spec explosion nightmare on your hands.

Related Articles:

    Post Footer automatically generated by Add Post Footer Plugin for wordpress.

    This entry was posted in bdd, mspec. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
    • http://therightstuff.de Alexander Groß

      James,

      Referring to your tweet, that post totally makes sense! :)

      Let me explain one technical detail: As you stated above the behavior specifications (VehicleThatHasBeenStartedBehaviors’ It fields) get injected into the respective context. From the console/TD.NET/HTML report you won’t be able to tell that “should have a running engine” came from a behavior, these are unaware of behaviors.
      The only place that is really aware of behavior specifications is the ReSharper runner that will show a sub-tree for each behavior that was injected into a context.

      Alex

    • http://www.lostechies.com/members/jagregory/default.aspx James Gregory

      @alex: That makes sense. I wouldn’t really want the behaviours to be exposed in the reports, as it’s just clouding the output; however, it is quite a nice touch in the R# runner. As you can (and I frequently do) use the R# runner to navigate around your specs, hiding away that certain ones are from a behaviour could easily lead to confusion.

      It’s a great feature, and I’m glad it’s there. It’s potentially open for abuse, but as are most great features.

    • http://craigcav.wordpress.com CraigCav

      James,

      I really like how behaviours can keep our code DRY, but I have a few reservations regarding the API – primarily that the Behaves_like field has/needs no value.

      I’ve written up my thoughts on my blog:
      http://craigcav.wordpress.com/2010/01/27/behaviours-in-mspec/

      Craig

    • http://codebetter.com/aaron.jensen Aaron Jensen

      Behaviors are actually not documented or mentioned on my blog on purpose. I figured someone would find it eventually, but I didn’t want to promote it. I actually considered removing it.

      One of the biggest goals of mspec and context/spec in general is to make the tests easily scannable. Behaviors breaks this. It plays to our (being geeks) need to apply tools and methods we know without considering context.

      DRY does *not* apply to tests the same way it applies to code. DRYing up your tests is local optimization at its finest. By doing it, you reduce the lines of code but you also reduce the ease of understanding and ability to scan the test files. Don’t get me wrong, some cruft still should be abstracted/hidden, but the *core* of your specs is the specifications themselves. Behaviors hide those behind another class making full understanding from the code an extremely jarring experience.

      Use with care.

    • http://www.lostechies.com/members/jagregory/default.aspx James Gregory

      I agree that you should use with care, definitely.

      As for DRY in tests, well, never is a strong word (although I don’t think you actually said never, but it was implied). It’s all about trade-offs. Readability over maintainability.

      Lets take an example that sparked this post. Fluent NHibernate exposes a Map method on ClassMap for mapping properties, this method is also available on the following: Components, DynamicComponents, CompositeElements, Subclasses, JoinedSubclasses, Joins, and probably others that I’m forgetting. I’ve got a few specs that cover the particular behaviour that method exposes, those specs are then repeated for each of those classes I just listed; technically they share the same implementation, but that’s an assumption that shouldn’t be made in my specs.

      Assuming I’ve got 5 specs for the Map method, that’s 35 specs for those classes listed. If I add a new piece of functionality that is spread across the many classes like Map is, I have to go through and create another 35+ specs; if I create another class similar to ClassMap, I have to recreate those 35 specs for the new implementation. Take that experience and multiply it by the 30+ methods and properties we expose on each of our classes, and you’ve got some serious spec explosion and a pending maintenance nightmare.

      In that scenario I’m much more willing to sacrifice a bit of readability in my specifications (and after all, it only affects the _code_, not the spec output) for the simplification of testing any additions/modifications that may be made to the interface. Without this functionality MSpec would be just as inadequate as any of the other testing frameworks, I’m happy it’s in there.

    • http://codebetter.com/aaron.jensen Aaron Jensen

      Hi James,

      It sounds like you’ve got a good use case for the feature. It also sounds like you understand the tradeoffs. That’s all I was really trying to point out. The feature is still there to be used, but people should understand the downsides. I did not say never, nor would I ever ;)

      Another thing to consider when being tempted to use this feature is that maybe this behavior should be broken into something separate that is testable once. It could be an indication that your class is doing too much and it’s time for composition rather than inheritance or some other refactoring. It doesn’t seem like this applies to your scenario, I just wanted to point that out as well–another thing to be aware of.

      I’m glad you’re enjoying MSpec and the behaves like feature, thanks for sharing your experiences.

    • http://www.lostechies.com/members/jagregory/default.aspx James Gregory

      Sorry, jumped on you a bit there. :)

      Agree with everything you said. If you are using behaves_like, there’s a very good chance your class is doing too much; in most cases I wouldn’t encourage it’s use for this exact reason.

      In FNH’s case, ClassMap is doing too much, but as the public API that’s it’s job; no matter how I slice it up underneath, ClassMap is always going to have to expose all these methods and thus always need testing. I could compose the ClassMap from various smaller classes and test those individually, but in the end I’d still need to test everything on ClassMap, because that’s what the public uses. So it’s specs galore no matter how I slice it.

      Thanks again for MSpec, keep up the good work.

    • Anon

      Just a note that your ” It should_have_a_running_engine = ” is duplicated both in the second example and the behaviours class.

    • Jeremy Wilkins

      What about being able to add the Act part to the behaviour definition:
      Because of = () =>
      vehicle.StartEngine();

      is there any way that this Act part can be isolated for commonality?
      I can see this as being useful given your example and having recently struggled with
      breaking DRY myself just as you are doing in your solution, but wouldn’t this be better?

      [Behaviors]
      public class StartingAVehicleBehaviors
      {
      protected static IVehicle vehicle;

      Because of = () => vechicle.StartEngine();

      It should_have_a_running_engine = () =>
      vehicle.IsEngineRunning.ShouldBeTrue();

      It should_be_polluting_the_atmosphere = () =>
      vehicle.IsPolluting.ShouldBeTrue();

      It should_be_idling = () =>
      vehicle.RevCount.ShouldBeBetween(0, 1000);
      }

      I ran info the need to simplify equality testing for IEquatable where it would be
      nice to do:

      [Behaviors]
      public class IsEqualBehavior
      {
      protected static IEquatable equatable;
      protected static IEquatable otherObject;
      protected static IEquatable isEqual;

      Because of = () => isEqual = equatable.Equals(otherObject);

      It should_be_equal = () => isEqual.ShouldBeTrue();
      }

      [Behaviors]
      public class IsNotEqualBehavior
      {
      protected static IEquatable equatable;
      protected static T otherObject;
      protected static bool isEqual;

      Because of = () => isEqual = equatable.Equals(otherObject);

      It should_not_be_equal = () => isEqual.ShouldBeFalse();
      }

      Although the type of T and the setup is guaranteed to be different, the
      implementation should most likely be constrained to the same behaviour
      despite the many uses of IEquatable.

      This also satisfies DRY much better.