Improving NUnit custom constraints with syntax helpers

! Warning: this post hasn't been updated in over three years and so may contain out of date information.

NUnit’s custom constraints support is a powerful feature for improving the quality and clarity of tests involving objects with complex state, yet – by themselves – the syntax is messy and difficult to read. However, a simple trick of using static methods can greatly enhance the readability of these constraints.

This article is an addendum to a two part series on custom constraints. If you haven’t already read them, you might find useful to do so before proceeding. Part one covers the pros and cons of single verses multiple asserts per test. Part two covers using custom constraints to solve the disadvantages of both approaches discussed in part one. If you are happy that you know about custom constraints on NUnit, then read on, or have already seen the article, then read on.

The previous article ended with the concludion that Assert.That(testBoard, new BoardMatchConstraint(expectedStateBoard)); was functional, but that it did not read well. NUnit has a solution to this, in that we can express asserts like this:

Assert.That(testValue, Is.EqualTo(expectedValue);

The class Is simply defines a set of static methods that return an instance of a child of the Constraint class. Whilst we cannot extend Is, there is nothing to stop us creating our own static helper class. By defining the following:

it becomes possible to rewrite the assert as:

Assert.That(testBoard, BoardState.Matches(expectedStateBoard));

The change is small, yet it makes things just that little bit more readable. Plus it has another advantage too. Imagine we have developed the game and its tests more and now we have a whole raft of custom assert classes. Rather than needing to remember all there names, we just expand the BoardState class with more helper methods:

In summary, this is what’s often termed syntactic sugar: it doesn’t add new testing functionality, it just makes the tests a little easier to write and a little easier to read. Considering how easy such classes are to write, it seems a worthwhile price to pay for that slight increase in ease of reading and writing tests.