May 28, 2004

Constraints in NUnit?

NUnit is progressing with version 2.2 in beta. It's coming along nicely, but eventually I'd like to see them use the Constraint concept from the dynamic mock libraries, instead of simple equality.

Origins

When Nat Pryce ported the Java Mock Objects library to Ruby, he started using blocks instead of simple equality to express assertions. When forced back to the static world of Java, he defined a Constraint interface, which I'll describe below. Then Joe and Chris used them in nMock, and then we all ported them back to jMock.

Constraints

public interface Constraint {
  public boolean eval(Object o);
  // also some stuff about writing out a description
}

A constraint will return true if an object passed to it meets its conditions. For example, a constraint for object identity is:

public class IsSame implements Constraint {
    private Object object;

    public IsSame( Object object ) { this.object = object; }
    public boolean eval( Object arg ) { return arg == object; }
    // and some self-describing stuff
}

In a test, the programmer chains constraints to describe the accepted behaviour. The assertion infrastructure will pass the actual value to each Constraint in turn and fail if any of them evaluate to false.

Constraints in xUnit?

With a little tweaking and some sugar, an xUnit assertion could be:

assert("frobble", lessThan(myFrobble), frobble); 

The Constraint can write out its own description, so we wouldn't have to write things like:

assert("frobble. Expected: " + myFrobble + " actual: " + frobble,
           myFrobble.compareTo(frobble) < 0);

to get meaningful failure messages.

It gets nicer when you compose Constraints or add more complex conditions:

assert("frobble", not(all(startsWith("red"))), frobble);

which means that frobble is actually a list of strings and we want to make sure that at least one of them starts with something other than "red". Again, the Constraints can write themselves out nicely.

The infrastructure could be slipped in nicely under the current API and exposed for people who want to be more complicated. I don't see any prospect of contributing to jUnit but, if I bide my time, I'm still hopeful for NUnit.

Posted by stevef at May 28, 2004 12:54 PM