Increase readability to assert IsNotNullOrEmpty with constraint-based asserts

Torbjörn Hansson picture Torbjörn Hansson · Apr 7, 2016 · Viewed 7.3k times · Source

I'm currently rewriting some unit tests to use NUnit 3 instead of NUnit 2 and need to change some asserts to contraint-based asserts. I have the following asserts:

Assert.IsNullOrEmpty(result);

That I've changed to:

Assert.That(result, Is.Null.Or.Empty);

However, I'm not totally pleased with the readability when asserting IsNotNullOrEmpty:

Assert.That(result, Is.Not.Null.And.Not.Empty);

My current suggestion is to create the following static class:

public static class Text
{
    public static EmptyConstraint IsNullOrEmpty => Is.Null.Or.Empty;

    public static EmptyConstraint IsNotNullOrEmpty => Is.Not.Null.And.Not.Empty;
}

Usage:

Assert.That(result, Text.IsNotNullOrEmpty);

This offers better readability at the expense of introducing a custom constraint. Is there a standard way of making the same assertion, or should I continue using Is.Not.Null.And.Not.Empty instead?

Answer

Sergey Kalinichenko picture Sergey Kalinichenko · Apr 7, 2016

Your assertion for Is.Null.Or.Empty reads perfectly fine without a Test class. Moreover, when this assertion fails, you know exactly what happened: you've got a valid string object that is not empty.

The issues I see with "DeMorgan-ized" version of its negation, i.e. Is.Not.Null.And.Not.Empty, are that it is too long, and it does not read nearly as nicely as Is.Null.Or.Empty does.

However, rather than making a separate constraint for it, I would assert its parts separately, i.e.

Assert.That(result, Is.Not.Null);
Assert.That(result, Is.Not.Empty);

The reason I would do it like that is that the two failure conditions do not overlap, i.e. result could be null, or it could be empty, but it cannot be both at the same time. A single compound assertion does not distinguish between these two situations, so you end up going for a debugger to see whether result was null or empty.

Separate assertions, on the other hand, tell you exactly what happens while remaining very readable. They "cost" you one extra line per assertion; I think this is a reasonable cost for getting more precise information about potential failures.