Tests are written for other developers to consume
When a CI build fails and a developer pulls up the test report, they should see an error message that clearly communicates what caused the test to fail. If an expectation was not met, the error message should explain what the expectation was, and what the actual result was. An error message like
Expected: True But was: False
is completely useless - we already know the test failed, what we want to know is why.NUnit constraint-based asserts are a wonderful tool for writing expectations into your tests that will give you the why. These fluent asserts help you write self-descriptive tests that fail in a descriptive way. Because there is so much already written about constraint-based asserts, we're not going to go into the basics in this blog post. If you're not already familiar with them, you should check out any of these great blog posts and get started! What we're going to take a look at today is one seemingly not as widely known constraint type - the collection constraint.
Collection constraints
Collection constraints were expanded in NUnit 2.4.6 to operate on any IEnumerable, and are incredibly useful! Before I started using collection constraints, to assert that a collection was not empty, I would write something like this:
Assert.That(collectionInstance.Count, Is.GreaterThan(0));
If this assertion fails, NUnit will print out
Expected: greater than 0 But was: 0
. This isn't a terrible error message, but it doesn't provide enough information. What we really want is a message that tells us we expected a collection with members, but got an empty collection. Let's try using a collection constraint:
Assert.That(collectionInstance, Is.Not.Empty);
That's very clear, isn't it? The error message is even more exciting:
Expected: not <empty> But was: <empty>
This tells us exactly what's going on! Let's check out some other frequently useful constraints:Collection contains a given member
Assert.That(collectionInstance, Has.Member(memberInstance));
Assert.That(collectionInstance, Has.Some.Matches(x => x.Id == expectedId));
Collection does not contain a given member
Assert.That(collectionInstance, Has.No.Member(memberInstance));
Assert.That(collectionInstance, Has.None.Matches(x => x.Id == expectedId));
Collection contains the same items as another collection
Assert.That(collectionInstance, Is.EquivalentTo(otherCollectionInstance));
Collection is a subset of another collection
Assert.That(collectionInstance, Is.SubsetOf(otherCollectionInstance));
Collection has no items in common with another collection
Assert.That(collectionInstance, Has.None.Matches(otherCollectionInstance.Contains));
Collection contains a member that is an instance of a given type
Assert.That(collectionInstance, Has.Some.InstanceOf<ExpectedType>());
Assert.That(collectionInstance, Has.Some.InstanceOf(expectedType));
Collection does not contains a member that is an instance of a given type
Assert.That(collectionInstance, Has.No.InstanceOf<ExpectedType>());
Assert.That(collectionInstance, Has.No.InstanceOf(expectedType));
Collection has a given number of members
Assert.That(collectionInstance, Has.Count.EqualTo(expectedCount));
There are plenty more collection constraints to assert nearly anything on a collection that you could think of. NUnit explains a lot of them - examples included - in their documentation. Very worthwhile reading, but not everything is in there. I highly suggest opening Visual Studio and playing around with the
Has
and Is
keywords if you want to see all the collection constraints that NUnit has to offer.