How to Use Assertion Scopes to Execute Multiple Assertions in C#

Written by willvelida | Published 2021/07/09
Tech Story Tags: csharp | dotnet | testing | unit-testing | programming | coding | c-sharp | c-programming

TLDR Fluent Assertions is a.NET library that provides use with a bunch of useful extension methods that allow us to test our C# code in a more natural way. Using Assertion Scopes, we can test our code in the same way without Fluent assertions using Assertion scopes. The library is a.NET library with a number of useful tools that can be used to test your code. For example, the test fails on the. Contain() method and the. HaveCount() method, but it has stopped running, but then fails on our assertion. AssertION Scopes can. fix this error.via the TL;DR App

Fluent Assertions is a .NET library that provides use with a bunch of useful extension methods that allow us to test our C# code in a more natural way.

Let's say for example we are testing the output of a string. Without Fluent Assertions, we might write something like this:

string testString = "hello";
string expectedOutput = testString.ToUpper();
Assert.Equal(expectedOutput, "HELLO");

If we were to write this test using Fluent Assertions, we could do so like this:

string testString = "hello";
string expectedOutput = testString.ToUpper();
expectedOutput.Should().Be("HELLO");

See? Much more natural 😊

Introducing Assertion Scopes

Let’s use a more extensive example. Say if I have a class that generates a shopping list like so:

public class ShoppingListGenerator
    {
        public static List<Item> GenerateItems()
        {
            return new List<Item>
            {
                new Item
                {
                    Name = "Apple",
                    Quantity = 5
                },
                new Item
                {
                    Name = "Banana",
                    Quantity = 1
                },
                new Item
                {
                    Name = "Orange",
                    Quantity = 3
                }
            };
        }
    }

For more complex unit tests, we may want to assert on multiple properties like so:

public class ShoppingListGeneratorShould
    {
        [Fact]
        public void MultipleAssertions()
        {
            var testShoppingList = ShoppingListGenerator.GenerateItems();

            testShoppingList.Should().NotBeNullOrEmpty();
            testShoppingList.Should().Contain(new Item { Name = "Cheese", Quantity = 2 });
            testShoppingList.Should().HaveCount(10);
            testShoppingList.Should().OnlyHaveUniqueItems();           
        }
    }

This approach is fine, but looking at our code, we can see that this test would fail on the assertion that our list will fail on the. Contain() method, since we don't have an item in our list that contains Cheese. This test would also fail on our. HaveCount() method, since we have only 3 items in our list, not 10.

Let's confirm our thinking by running our test.

We were correct! But in this example, not only has our test failed against our .Contains() method, but it has stopped running our test!

Imagine that we fix this error so that the assertion passes, but then fails on the next assertion. And the next one, then the next one and so forth.

Testing our code like this would be rather tedious. Thankfully we can fix this using an Assertion Scope!

Using Assertion Scopes, we can batch multiple assertions into a AssertionScope so that FluentAssertions will only throw the one exception at the end of the scope with all of our failures.

Let's change our test to use an Assertion Scope.

using AssertionScopes;
using FluentAssertions;
using FluentAssertions.Execution;
using System;
using Xunit;

namespace Tests
{
    public class ShoppingListGeneratorShould
    {
        [Fact]
        public void MultipleAssertions()
        {
            var testShoppingList = ShoppingListGenerator.GenerateItems();

            using (new AssertionScope())
            {
                testShoppingList.Should().NotBeNullOrEmpty();
                testShoppingList.Should().Contain(new Item { Name = "Cheese", Quantity = 2 });
                testShoppingList.Should().HaveCount(10);
                testShoppingList.Should().OnlyHaveUniqueItems();
            }                     
        }
    }
}

We are now wrapping our Assertions in a using statement and our exception will only be thrown at the point of disposing our AssertionScope.

Let's run the test and see what happens!

Our test has failed, but here we now get both exceptions thrown back to us!

Message: 
    Expected testShoppingList {AssertionScopes.Item
       {
          Name = "Apple"
          Quantity = 5
       }, AssertionScopes.Item
       {
          Name = "Banana"
          Quantity = 1
       }, AssertionScopes.Item
       {
          Name = "Orange"
          Quantity = 3
       }} to contain 
    
    AssertionScopes.Item
    {
       Name = "Cheese"
       Quantity = 2
    }.
    Expected testShoppingList to contain 10 item(s), but found 3.

Now instead of having to run and re-run our tests each time an assertion fails in our test, we can see all the assertions that are failing in a test at once!

Conclusion

Fluent Assertions is a great library that allows us to write our C# tests in a more natural and expressive way. Assertion Scopes make our lives easier when using multiple assertions within our unit tests by saving us time and effort when finding out why our tests are failing.

If you want to learn more about Fluent Assertions, check out the docs here: https://fluentassertions.com/about/

Hopefully, you found this article useful! As always, if you have any questions, feel free to comment below or ask me on Twitter!

Happy Coding! 💻👨‍💻👩‍💻

Also published on: https://dev.to/willvelida/using-assertion-scopes-to-execute-multiple-assertions-3029


Written by willvelida | Customer Engineer at Microsoft based in Auckland, New Zealand
Published by HackerNoon on 2021/07/09