About me

Michael L Perry

Improving Enterprises

Principal Consultant

@michaellperry

User login

Predassert

I was inspired by Robert C. Martin’s Clean Code to fix a problem with Microsoft’s unit testing framework. Assert.AreEqual(object expected, object actual). How do you remember which is the expected value and which is the actual?

In JUnit and it’s younger .NET cousin NUnit, the method name makes it a bit more clear. Assert.assertEquals(Object expected, Object actual). The code reads more like a sentence (albeit one spoken by Yoda).

assertEquals(3, theResult);

I was further inspired by BDD systems like NSpec, which makes the code more grammatically correct.

Specify.That( theResult ).ShouldEqual( 3 );

Readability of the code is only one of the concerns. The other is readability of the unit test failures. Assert.AreEqual() writes out a good failure message, because it can give you both the expected and the actual value. But more complex assertions do not provide useful failure messages. To solve these issues within the Microsoft unit testing space, I created Predassert.

Yet another library with a class named “Is”

The primary goal of Predassert is that one line of code expresses both a predicate and an assertion. A predicate is executable and can determine if something is true or false. An assertion is human readable and explains why a test fails.

Predassert accomplishes this goal through a fluent interface.

Pred.Assert( theResult, Is.EqualTo(3) );

The “Is” class declares several static methods that generate assertion predicates. For example:

Pred.Assert( new List<Person>(), Is.Empty<Person>() );
Pred.Assert( referenceA, Is.SameAs(referenceB) );
Pred.Assert( bob, Is.NotNull<Person>() );

You also have “Has” for properties and “Contains” for collections.

Pred.Assert( bob, Has<Person>.Property(person => person.Name, Is.EqualTo("Bob") );
Pred.Assert( queue, Contains<GameRequest>.That(Has<GameRequest>.Property(
    request => request.Person, Is.SameAs(bob))));

You can even combine predicates with “And”.

Pred.Assert(bob,
    Has<Person>.Property(person => person.FirstName, Is.EqualTo("Bob")
    .And(Has<Person>.Property(person => person.LastName, Is.EqualTo("Perry"))
);

As you can see, you can get pretty carried away.

Uniformity of expression

The fluent interface is not the goal. Uniformity of expression is the goal. The fluent interface is just a means to that end. When you use Microsoft’s unit testing framework, Assert.IsTrue(bool condition, string message) makes you express the assertion in both code and text. But when you use Predassert, the fluent interface generates both from the same syntax.

The “Has” class will insert the property name into the assertion message. There is no need to retype it, no chance of copy/paste errors, and no extra work if you use the “Rename” refactoring tool.

The “Contains” class will enumerate the collection and explain why each element failed the test. This extra detail usually gives you enough information to diagnose an error directly from the failure message, rather than by setting breakpoints.

Predassert is currently distributed as part of the Correspondence library on CodePlex. I’m allowing it to grow organically as I need features. When it is more mature, perhaps I will separate it. Until then, you can download the Correspondence source code and extract the Predassert project for your own use.