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.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!

6 thoughts on “Better testing experience with Shouldly

  1. If you have a project where you already have lots of tests in MSTest then it’s not likely to be worth the effort to convert them over to NUnit or XUnit because the time spent won’t create a good return on investment. This was exactly the situation I was in at my old company when I wrote this post:

    http://zombiecodekill.com/2014/02/23/survival-tips-for-living-with-mstest/

    If you’re doing a new application, or even just a new test project as part of an existing application, it well worth making the switch in my opinion. But I haven’t tried Shouldly myself yet and it does look good based on this post.

    Like

  2. I also really love the ‘ShouldSatisfyAllConditions’ method that lets you write more readable tests!

    nbrExchangeRates.ShouldSatisfyAllConditions
    (
    () => nbrExchangeRates.ShouldBeOfType(typeof(Int32)),
    () => nbrExchangeRates.ShouldBeGreaterThan(0),

    );

    Like

    • I have used NUnit a few times and a bit of XUnit, for the moment I do not know them well enough to be able to compare them but they definitely seem more complete than MSTest.
      I think it is also possible to combine them with a fluent assertions library, like Shouldly, as well.

      I know that I have to learn more about these two frameworks, it is on my “TODO” list.

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s