NUnit assertions - constraint model and classic model
If you are using NUnit for your unit tests, there are two models for writing assertions. The "old skool" way of writing assertions is like
Assert.IsTrue(a == 5);
Assert.AreEqual(expectedValue, result);
This way of writing assertions is well known and is used in most unit testing frameworks. Some years ago, NUnit started introducing a new assertion model.
Constraint model
The equivalent assertions in the new constraint model are
Assert.That(a, Is.EqualTo(5));
Assert.That(result, Is.EqualTo(expectedResult);
When the constraint model was introduced, it seemed like nothing more than syntactical sugar. I didn't see any real benefit to it and continued using the classic model.
The constraint model has however been refined and extended over the past years. New and clever ways of writing assertions have been introduced to the constraint model, while the classic model has not evolved.
Rather than writing complex asserts, there is now a number of useful asserts on collections like
Assert.That( iarray, Is.All.GreaterThan(0) );
Assert.That( myArray, Is.SubsetOf( largerArray ) );
Assert.That( sarray, Is.Ordered.Descending );
Assert.That( sarray, Has.No.Member("x") );
Assert.That( iarray, Has.Some.GreaterThan(2) );
Assert.That( iarray, Is.All.GreaterThan(0) );
The meaning of these asserts are pretty self-explaining because of the new syntax.
The constraints typically have additional modifiers. For example, for comparing two doubles, one would often provide a tolerance in the classic model in order to cope with floating-point round-off errors:
Assert.AreEqual(expectedValue, result, 0.000001)
Where the tolerance often was somewhat arbitrary and dependent on the expected value.
With the new constraint model, this can be made much more robust by specifying it like
Assert.That(result, Is.EqualTo(expectedResult).Within(0.01).Percent
Assert.That(result, Is.EqualTo(expectedResult).Within(2).Ulps
The "Ulps" tolerance is quite interesting. "Ulp" means "Units in the Last Place" and is more robust for allowing numerical inaccuracies that are introduced than using a fixed tolerance.
The list of constraints is too long to replicate here. The full set of constraints is listed in the NUnit documentation here: https://github.com/nunit/nunit/wiki/Constraints.
The constraints typically have additional modifiers. For example, for comparing two doubles, one would often provide a tolerance in the classic model in order to cope with floating-point round-off errors:
Assert.AreEqual(expectedValue, result, 0.000001)
Where the tolerance often was somewhat arbitrary and dependent on the expected value.
With the new constraint model, this can be made much more robust by specifying it like
Assert.That(result, Is.EqualTo(expectedResult).Within(0.01).Percent
Assert.That(result, Is.EqualTo(expectedResult).Within(2).Ulps
The "Ulps" tolerance is quite interesting. "Ulp" means "Units in the Last Place" and is more robust for allowing numerical inaccuracies that are introduced than using a fixed tolerance.
The list of constraints is too long to replicate here. The full set of constraints is listed in the NUnit documentation here: https://github.com/nunit/nunit/wiki/Constraints.
Custom constraints
If you happen to write your own classes (!), you may need to be able to compare them using a less strict method than the Equals(). For example, you may need to compare mathematical vectors within a tolerance.
Rather than using three asserts for a 3-dimensional vector, you can write your own constraints with a given tolerance.
The classic model is disappearing
Until now, NUnit has been fully backwards compatible. The developer has had the choice to use the classic model if desired. Starting in version 3.0, however, some of the classic assertions have disappeared. For example, the Assert.IsNullOrEmpty() has been removed.
I don't know if the classic assertion model will eventually be completely retired. Who cares anyway, when the constraint model is so much better? ;-)
I don't know if the classic assertion model will eventually be completely retired. Who cares anyway, when the constraint model is so much better? ;-)
No comments:
Post a Comment