In my last project quite some time was spent improving the readability of our unit tests. For this reason we have created a number of 'Should()' extension methods for several .NET types. Through this 'Should()' method you get access to a custom assertion class with assertions that are specific for that type. This way we are able to do the necessary assertions in a readable and more intention revealing way (OK, that is debatable, but that is how we see it).
The next table shows some examples of how you can do the assertions 'the old way' by using the Assert class, and how it will look when you use the Should() extensions.
| Old way by using Assertion class |
With Should() extension method |
| Assert.AreEqual(1, products.First().Key); |
products.First().Key.Should().Equal(1); |
| Assert.AreEqual(10, products.Count()); |
products.Should().HaveCount(10); |
| Assert.IsTrue(person.Birthdate > DateTime.Today) |
person.Birthdate.Should().BeAfter(DateTime.Today); |
| CollectionAssert.Contains(products, newProduct); |
products.Should().Contain(newProduct); |
You can also chain several assertions by using the 'And' constraint like this:
product.Code.Should()
.HaveLength(10).And.StartWith("PC").And.EndWith("54");
There is also a 'ShouldThrow()' extension method that can be used to specify that a specific exception is expected when calling a method.
fileSystem.ShouldThrow(x => x.Open(@"C:\not_existing_file.txt"))
.Exception<FileNotFoundException>()
.WithMessage("Could not find file 'C:\not_existing_file.txt");
For all assertions you can supply a reason that states why you would expect this. In case of a failing test, the custom assertions classes will use this reason to compose a readable description of what was expected and why, and what was actually detected. For example:
product.Code.Should()
.StartWith("PC", "because that is what the code for products from
the 'Computers' category should start with");
If this assertion should fail, the following error message will be generated:
"Expected string starting with <PC> because that is what the code for products from the 'Computers' category should start with, but found <AB123>."
The Should extensions have been put in a separate project that you can easily use in your solution. It is very easy to extend the custom assertions, or to create a 'Should()' extension method with corresponding custom assertions for your own classes.
Download the Custom assertions library