Better testing experience with Shouldly

Shouldly Logo
Shouldly Logo

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.ShouldBeInRange(0, 10);
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.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;

Of course this test fails, and generates the following error message:

        should be greater than
        but was

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});
        should be
    [1, 2, 3]
        but was
    [1, 2, 4]
    [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());
        not throw 
        but does
Should.CompleteIn(() => LongMethod(), TimeSpan.FromMilliseconds(50));
        should complete in
        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!