
I am a strong believer in unit testing, I like to write lots of tests for my code in order to make sure I do not regress when implementing new features on my projects. I love having a safety net when working.
Then it is important to make sure that the tests are easy to write and that they give a good feedback when failing. When a test fails you should be able to know exactly where the code under test has an incorrect behavior to fix it as soon as possible.
Shouldly is a .NET assertion library very helpful for this matter, it provides a lot of extensions for various types making them easy to test. It is available on GitHub and as a Nuget package:
Install-Package Shouldly
Simple assertions
Let’s dive into the topic to see how it can be used, I’ll start with simple assertions on an integer value:
var value = 5; value.ShouldBe(5); value.ShouldBeGreaterThan(4); value.ShouldBeGreaterThanOrEqualTo(5); value.ShouldBeInRange(0, 10); value.ShouldBeLessThan(6); value.ShouldBeOneOf(2, 5, 7);
It is as simple as that, not need for any Assert method, Shouldly does it for you. And there are many more extensions to test about everything you want.
Now, we can have a look at the assertions available for the string type:
var myString = "foo"; myString.ShouldNotBeEmpty(); myString.ShouldNotBe(null); myString.ShouldStartWith("f"); myString.ShouldEndWith("oo"); myString.ShouldNotContain("bar"); myString.ShouldBe("FOO", Case.Insensitive);
Likewise, Shouldly offers various methods in order to test a string value to make sure everything behaves as expected.
The library offers also some assertions to check the behavior of a method through actions:
Should.NotThrow(() => SuccessMethod()); Should.CompleteIn(() => SuccessMethod(), TimeSpan.FromMilliseconds(50));
As you can see you can write performances tests for your methods using the CompleteIn() method.
Specific error messages
Now that we have written some tests using Shouldly, let’s have a look at what happens when a test fails. As I said it is important to have comprehensive error messages when an error occurred in order to be able to debug quickly.
int value = 5; value.ShouldBeGreaterThan(6);
Of course this test fails, and generates the following error message:
value should be greater than 6 but was 5
I find that this message is quite clear and gives us a good understanding of what went wrong, it even contains the name of the tested variable. Now let’s see how is the message with an enumerable.
var numbers = new[] { 1, 2, 4 }; numbers.ShouldBe(new []{1, 2, 3});
numbers should be [1, 2, 3] but was [1, 2, 4] difference [1, 2, *4*]
The library highlights the difference for us, again I find the message pretty clean, especially when you compare it with the MSTest version:
var numbers = new[] { 1, 2, 4 }; CollectionAssert.AreEqual(new[] { 1, 2, 3 }, numbers);
CollectionAssert.AreEqual failed. (Element at index 2 do not match.)
Here are a few more examples.
Should.NotThrow(() => FailingMethod());
Should not throw System.ApplicationException but does
Should.CompleteIn(() => LongMethod(), TimeSpan.FromMilliseconds(50));
Task should complete in 00:00:00.0500000 but did not
Shouldly is easy to install and easy to use and, in my opinion, makes testing code much clearer. It provides a lot of helpful extensions and if you find that one is missing you can contribute to the project to make it available to everyone.
I think that testing code should be treated with the same respect than production code and this is why it should me made as clean as possible and as understandable as possible, this way your tests are a part of the documentation of your code.
See you next time!