Blog

NUnit 2.4 constraints

April 13, 2007

The forthcoming release of NUnit 2.4 supports a constraint-based syntax for assertions. Don't worry, the old syntax (classic model) is still going to be available for a long time to come (they even did some further enhancements). If you have used Rhino Mocks for mocking interfaces and classes in your unit tests, then you should be already familiar with a constraint-based design.

The following unit test shows a simple example:

[Test]
public void Add_TwoIntegers_CheckResult()
{
    Int32 result = Calculator.Add(96, 4);
    Assert.That(result, Is.EqualTo(100)); 
}

The classic "Hello Pluto" example just to illustrate the clean syntax and fluent interface of the new assertion model. You can also make use of a few constraint modifiers:

[Test]
public void Add_TwoDoubles_CheckResult()
{
    Double result = Calculator.Add(96.0, 4.0);
    Assert.That(result, Is.EqualTo(100.0).Within(0.0002));
}

It's even possible to combine constraints:

[Test]
public void GetSomething_CheckNotNullAndNotEmpty()
{
    String result = Subject.GetSomeString();
    Assert.That(result, Is.Not.Null & Is.Not.Empty);
}

Man, don't you just love this syntax! It's almost unnecessary to mention that NUnit 2.4 delivers a whole lot of constraint classes out-of-the-box. But now comes the fun part. What's really interesting is that it's very easy to write your own custom constraints. Every constraint derives from the Constraint base class which in turn implements IConstraint.

In order to try something out, I've created a constraint class like the CollectionEquivalentConstraint but for DataTables instead of collections. Those of you who know me are scratching their heads after reading this last sentence. My dislike of the DataSet, DataTable and their related classes is widely known but this would bring us off-topic. I thought it would make a nice example. Here goes ...

I derived a class from NUnit.Framework.Constraints.Constraint and created an override for the Matches method:

public override Boolean Matches(Object actual)
{
    base.actual = actual;

    DataTable actualDataTable = actual as DataTable;
    Boolean result = (null != actualDataTable);
    result &= IsSubsetOf(actualDataTable, _expected);
    result &= IsSubsetOf(_expected, actualDataTable);

    return result;
}

The IsSubsetOf method determines whether the first specified DataTable (subset) is a subset of the second specified DataTable (superset):

private Boolean IsSubsetOf(DataTable subset, 
                           DataTable superset)
{
    // Check if the number of columns are different
    if(subset.Columns.Count != superset.Columns.Count)
    {
        return false;
    }

    // Check if the specified superset contains the
    // DataColumns of the specified subset and if 
    // they support the same data type.
    foreach(DataColumn dataColumn in subset.Columns)
    {
        Int32 dataColumnIndexInSuperset = 
            superset.Columns.IndexOf(dataColumn.ColumnName);
        if(-1 == dataColumnIndexInSuperset)
        {
            return false;
        }

        if(dataColumn.DataType != 
           subset.Columns[dataColumnIndexInSuperset].DataType)
        {
            return false;
        }
    }

    // Check if the data rows of the specified subset
    // are contained by the specified superset.
    foreach(DataRow dataRow in subset.Rows)
    {
        if(!IsDataRowInDataTable(dataRow, superset))
        {
            return false;
        }
    }    

    return true;
}

Notice that the IsSubsetOf method is private. If I wanted to create a DataTableSubsetConstraint class (like CollectionSubsetConstraint) I could move the IsSubsetOf method into a base class.

This way it's possible to write your own constraints that you can use for your own unit tests. You can start exploring the constraints model in NUnit by using the greatest documentation tool ever build: Reflector.

Update 23/04/2007:

You can download the source code here. Note that this code is just for trying out some of the new features of NUnit 2.4 and should only be used as an example.

If you and your team want to learn more about how to write maintainable unit tests and get the most out of TDD practices, make sure to have look at our trainings and workshops or check out the books section. Feel free to reach out at infonull@nullprincipal-itnull.be.

Profile picture of Jan Van Ryswyck

Jan Van Ryswyck

Thank you for visiting my blog. I’m a professional software developer since Y2K. A blogger since Y2K+5. Provider of training and coaching in XP practices. Curator of the Awesome Talks list. Past organizer of the European Virtual ALT.NET meetings. Thinking and learning about all kinds of technologies since forever.

Comments

About

Thank you for visiting my website. I’m a professional software developer since Y2K. A blogger since Y2K+5. Author of Writing Maintainable Unit Tests. Provider of training and coaching in XP practices. Curator of the Awesome Talks list. Thinking and learning about all kinds of technologies since forever.

Contact information

(+32) 496 38 00 82

infonull@nullprincipal-itnull.be