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

A few people have asked me for more details on the specification extension methods we use to make our BDD tests more readable.  As I mentioned previously, SpecUnit.net is a great library that has all kinds of useful extension methods, but it’s written to be used on top of xUnit.net.  If you want to use the technique in the MSTest framework, you’ll have to implement your own spec extension methods.

Fortunately, they’re trivial to write.  Here’s an example of what we wrote for object references, which actually covers the majority of tests since our observations are often just testing for equality (or not) and nullness (or not).

/// <summary>

/// Provides BDD-style assertations for object references.

/// </summary>

public static class ObjectSpecificationExtensions

{

    /// <summary>

    /// Verifies that the object reference is null.

    /// </summary>

    /// <param name="actual">The reference to verify.</param>

    public static void ShouldBeNull(this object actual)

    {

        Assert.IsNull(actual);

    }

 

    /// <summary>

    /// Verifies that the object reference is not null.

    /// </summary>

    /// <param name="actual">The reference to verify.</param>

    public static void ShouldNotBeNull(this object actual)

    {

        Assert.IsNotNull(actual);

    }

 

    /// <summary>

    /// Verifies that two objects are equal.

    /// </summary>

    /// <param name="actual">The actual object.</param>

    /// <param name="expected">The expected object.</param>

    public static void ShouldEqual(this object actual, object expected)

    {

        Assert.AreEqual(expected, actual);

    }

 

    /// <summary>

    /// Verifies that two objects are not equal.

    /// </summary>

    /// <param name="actual">The actual object.</param>

    /// <param name="notExpected">The unexpected object.</param>

    public static void ShouldNotEqual(this object actual, object notExpected)

    {

        Assert.AreNotEqual(notExpected, actual);

    }

 

    /// <summary>

    /// Verifies that two objects are the same instance.

    /// </summary>

    /// <param name="actual">The actual object.</param>

    /// <param name="expected">The expected object.</param>

    public static void ShouldBeTheSameAs(this object actual, object expected)

    {

        Assert.AreSame(expected, actual);

    }

 

    /// <summary>

    /// Verifies that two objects are not the same instance.

    /// </summary>

    /// <param name="actual">The actual object.</param>

    /// <param name="notExpected">The unexpected object.</param>

    public static void ShouldNotBeTheSameAs(this object actual, object notExpected)

    {

        Assert.AreNotSame(notExpected, actual);

    }

 

    /// <summary>

    /// Verifies that an object is of a specific type.

    /// </summary>

    /// <param name="actual">The actual object.</param>

    /// <param name="expected">The expected type.</param>

    public static void Is(this object actual, Type expected)

    {

        Assert.IsInstanceOfType(actual, expected);

    }

 

    /// <summary>

    /// Verifies that an object is not a specific type.

    /// </summary>

    /// <param name="actual">The actual object.</param>

    /// <param name="expected">The unexpected typ.</param>

    public static void IsNot(this object actual, Type notExpected)

    {

        Assert.IsNotInstanceOfType(actual, notExpected);

    }

}

We also have extensions for specific types (Int32, String, TimeSpan, Single, etc) that implement things like ShouldBeGreaterThan(), ShouldBeLessThan(), ShouldBeEmpty(), ShouldBeCloseTo(), etc.  The nice thing about this strategy is that we don’t have to have our entire spec extension library written up front.  If we’re writing a test and want to assert some condition that isn’t already implemented by a spec extension method, we can just add an appropriate extension method at that point.

The extension methods above are all a single line that just pass the call through to the MSTest Assert class, but spec extensions are even more helpful when you have a complex assertion that requires multiple lines of code to express.  You can hide all that complexity behind a nice intention-revealing extension method that leaves your tests crisp and easy to understand.