Unit Test – Fluent Assertions

By | 18/10/2023

In this post, we will see what “Fluent Assertions” is and how we can use it in our projects.
But first of all, what is “Fluent Assertions”?
Fluent Assertions is a popular library for writing more expressive and readable unit tests in C#.
It provides a fluent, natural language syntax for asserting the behaviour of our code.
For all information, we can consult the official web site.

We start to create a xUnit Test project and then, we add the Fluent Assertions NuGet package to the project, using the command:

Install-Package FluentAssertions

Now, we are ready to use “Fluent Assertion” in our tests but, before to start, I want to highlight that we will create very easy tests because, the goal of this post is not the tests creations but, how to use “Fluent Assertion”.


BASIC ASSERTIONS:

using FluentAssertions;
using Xunit;

namespace FluentAssertionsTest
{
    public class Calculator
    {
        public int Add(int val1, int val2)
        {
            return val1 + val2;
        }
    }


    public class TestFluentAssertions
    {
        // Basic Assertions
        [Fact]
        public void Add_Should_Return_Correct_Sum()
        {
            // Arrange
            var calculator = new Calculator();

            // Act
            int result = calculator.Add(2, 3);

            // Assert
            // Fluent assertion: Check if result is 5
            result.Should().Be(5); 
        }
    }
}


If we run the application, the following will be the result:


CHAINING ASSERTIONS:

using FluentAssertions;
using Xunit;

namespace FluentAssertionsTest
{
    public class Calculator
    {
        public int Add(int val1, int val2)
        {
            return val1 + val2;
        }

        public double Divide(int val1, int val2)
        {
            return val1 / val2;
        }
    }


    public class TestFluentAssertions
    {
        // Chaining Assertions
        [Fact]
        public void Divide_Should_Return_Correct_Result()
        {
            // Arrange
            var calculator = new Calculator();

            // Act
            double result = calculator.Divide(10, 2);

            // Assert
            result.Should()
                  .Be(5) // Check if result is 5
                  .And
                  .BeGreaterThan(4) // Check if result is greater than 4
                  .And
                  .BeLessOrEqualTo(6); // Check if result is less than or equal to 6
        }
    }
}


If we run the application, the following will be the result:


COLLECTION ASSERTIONS:

using FluentAssertions;
using System.Collections.Generic;
using Xunit;

namespace FluentAssertionsTest
{
    public class TestFluentAssertions
    {
        // Collection Assertions
        [Fact]
        public void Check_List_Contents()
        {
            // Arrange
            var numbers = new List<int> { 1, 2, 3, 4, 5 };

            // Assert
            numbers.Should()
                   .Contain(3) // Check if the list contains 3
                   .And
                   .HaveCount(5) // Check if the list has 5 elements
                   .And
                   .NotContain(6) // Check if the list does not contain 6
                   .And
                   .OnlyHaveUniqueItems(); // Check if all items are unique in the list
        }
    }
}


If we run the application, the following will be the result:


STRING ASSERTIONS:

using FluentAssertions;
using System.Collections.Generic;
using Xunit;

namespace FluentAssertionsTest
{
    public class TestFluentAssertions
    {
        // String Assertions
        [Fact]
        public void StringAssertions()
        {
            // Arrange
            string greeting = "Hello, World";

            // Assert
            greeting.Should()
                    .StartWith("Hello") // Check if the string starts with "Hello"
                    .And
                    .EndWith("World") // Check if the string ends with "World"
                    .And
                    .Contain("o,") // Check if the string contains "o,"
                    .And
                    .HaveLength(12); // Check if the string has a length of 12
        }
    }
}


If we run the application, the following will be the result:


OBJECT EQUALITY:

using FluentAssertions;
using Xunit;

namespace FluentAssertionsTest
{
    public class Person 
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

    public class TestFluentAssertions
    {
        // Object Equality
        [Fact]
        public void ObjectEquality()
        {
            // Arrange
            var person1 = new Person { FirstName = "John", LastName = "Doe" };
            var person2 = new Person { FirstName = "John", LastName = "Doe" };

            // Assert
            person1.Should().BeEquivalentTo(person2); // Check if properties of objects are equal
        }
    }
}


If we run the application, the following will be the result:


EXCEPTION ASSERTIONS:

using FluentAssertions;
using System;
using Xunit;

namespace FluentAssertionsTest
{
    public class Calculator
    {
        public int Add(int val1, int val2)
        {
            return val1 + val2;
        }

        public double Divide(int val1, int val2)
        {
            return val1 / val2;
        }
    }

    public class TestFluentAssertions
    {
        // Exception Assertions
        [Fact]
        public void ExceptionAssertions()
        {
            // Arrange
            var calculator = new Calculator();

            // Act & Assert
            Action act = () => calculator.Divide(10, 0);

            // Assert that an exception of type DivideByZeroException is thrown
            // with the specified error message.
            act.Should()
               .Throw<DivideByZeroException>()
               .WithMessage("Attempted to divide by zero.");
        }
    }
}


If we run the application, the following will be the result:


NULLABLE TYPE ASSERTIONS:

using FluentAssertions;
using Xunit;

namespace FluentAssertionsTest
{
    public class TestFluentAssertions
    {
        // Nullable Type Assertions
        [Fact]
        public void NullableTypeAssertions()
        {
            // Arrange
            int? nullableValue = null;

            // Assert that the nullableValue does not have a value (is null)
            nullableValue.Should().NotHaveValue();
        }
    }
}


If we run the application, the following will be the result:


DATE TIME ASSERTIONS:

using FluentAssertions;
using System;
using Xunit;

namespace FluentAssertionsTest
{
    public class TestFluentAssertions
    {
        // DateTime Assertions
        [Fact]
        public void DateTimeAssertions()
        {
            // Arrange
            DateTime now = DateTime.Now;
            DateTime later = now.AddMinutes(5);

            // Assert that 'later' is after 'now' and that it is within 6 minutes
            // after 'now'.
            later.Should().BeAfter(now)
                 .And
                 .BeWithin(TimeSpan.FromMinutes(6)).After(now);
        }
    }
}


If we run the application, the following will be the result:



“Fluent Assertions” is a valuable tool for writing expressive and readable unit tests in C#.
Its natural language syntax makes it easier to convey the intent of our tests, and its extensive set of assertions allows us to cover a wide range of scenarios.
By adopting “Fluent Assertions”, we can enhance the quality of our unit tests and make our codebase more robust.


Leave a Reply

Your email address will not be published. Required fields are marked *