Combine xUnit with Fluent Assertions
Tags: csharp, dotnet
Published: 2019-11-25 01:46:42

---
title: Combine xUnit with Fluent Assertions
published: true
description: Combining xUnit with Fluent Assertions library
tags: #csharp #dotnet #bestofdev
---
***
*Welcome!* Spanish articles on [LinkedIn](https://www.linkedin.com/in/mpetrinidev/). You can follow me on [Twitter](https://twitter.com/mpetrinidev/) for news.
***

# xUnit

One of the most popular frameworks to test code in the .NET ecosystem is xUnit.

[xUnit.net](https://xunit.net/) is a free, open-source, community-focused unit testing tool for .NET.

## A common situation using xUnit

xUnit uses the `Assert` class to verify conditions during the process of running tests. This class provides various extensions methods that commonly use two parameters: 

* Expected value
* Actual value

Let's see an example.

```cs
    var variable = 1;

    Assert.Equal(10, variable);
    Assert.Equal(variable, 10);
```

So, which one of these `Assert.Equal` methods are correct? When we mix up the expected and the actual value parameters, if the test fails, the failure message may not make much sense.

In the first case, we get the correct message.

> Assert.Equal() Failure
> Expected: 10
> Actual:   1

The second one is incorrect cause are expecting 10, not 1

> Assert.Equal() Failure
> Expected: 1
> Actual:   10

# Fluent Assertions

[Fluent Assertions](https://fluentassertions.com/) is a library that provides us:

* Clearer explanations about why a test failed
* Improve readability of test source code

Basically, with this library, we can read a test more like an English sentence.

If we perform the same test using Fluent Assertions library, the code will look something like this:

```cs
    var variable = 1;
            
    variable.Should().Be(10);
```

Let's take a look at the failure message.

> Expected variable to be 10 but found 1.

This message is clearer than the Assert failure message. A more descriptive failure message may prevent the need for debugging through the test.

# Let's dive into some examples

## Inline asserts

We could write our asserts inline using the `And` constraint of fluent assertions.

```cs
    [Fact]
    public void xUnit_StringTest()
    {
        string code = "001SUMMERCODE";

        Assert.NotNull(code);
        Assert.NotEmpty(code);
        Assert.StartsWith("001", code);
        Assert.EndsWith("code".ToUpper(), code);
    }

    [Fact]
    public void xUnit_FluentAssertions_StringTest()
    {
        string code = "001SUMMERCODE";

        //code.Should().NotBeNullOrEmpty();
        //code.Should().StartWith("001");
        //code.Should().EndWithEquivalent("code");

        code.Should().NotBeNullOrEmpty().And.StartWith("001").And.EndWithEquivalent("code");
    }
```

## Custom messages

The `because` parameter allows us to set a custom message when a test fails.

```cs
    [Fact]
    public void xUnit_FluentAssertions_CustomMessageTest()
    {
        string code = "002SUMMERCODE";

        code.Should().NotBeNullOrEmpty().And.
            StartWith("001", because: "the first batch of codes start with 001").And.
            EndWithEquivalent("code");
    }
```

Output

> Expected code to start with 
> "001" **because the first batch of codes start with 001**, but 
> "002SUMMERCODE" differs near "2SU" (index 2).

## Assertion scope

If we have multiple asserts and one fails, the next ones do not execute.  This is the default behavior, but we can change it through the `AssertionScope.`

```cs
    [Fact]
    public void xUnit_FluentAssertions_StringTest()
    {
        string code = "001SUMMERCODE";
        
        code.Should().NotBeNullOrEmpty();
        code.Should().StartWith("002"); //fails
        code.Should().EndWithEquivalent("code");
        code.Should().ContainEquivalentOf("SUMMERS");//fails
    }
```

Output 

> Expected code to start with 
> "002", but 
> "001SUMMERCODE" differs near "1SU" (index 2).

Using AssertionScope

```cs
    [Fact]
    public void xUnit_FluentAssertions_StringTest()
    {
        string code = "001SUMMERCODE";

        using (new AssertionScope())
        {
            code.Should().NotBeNullOrEmpty();
            code.Should().StartWith("002"); //fails
            code.Should().EndWithEquivalent("code");
            code.Should().ContainEquivalentOf("SUMMERS"); //fails
        }
    }
```

Output

> Expected code to start with 
> "002", but 
> "001SUMMERCODE" differs near "1SU" (index 2).
> Expected code to contain equivalent of 
> "SUMMERS" but found 
> "001SUMMERCODE".

The difference is that with `AssertionScope,` we run all asserts.

## Exceptions

The `Throw` and `ThrowExactly` methods help us to test if a method throws an exception. I recommend using `ThrowExactly` because `Throw` pass tests when check inheritance.

Let's define a `Person` class.

```cs
    public class Person
    {
        public string Name { get; }

        public Person(string name)
        {
            Name = name ?? throw new ArgumentNullException(nameof(name));
        }
    }
```

Then, test the constructor to throw the ArgumentNullException using `Throw.`

```cs
    [Fact]
    public void xUnit_FluentAssertions_ExceptionTest()
    {
        Action act = () => new Person(null);
        
        act.Should().Throw<Exception>()
            .WithMessage("Value cannot be null. (Parameter 'name')");
    }
```

That's a successful test!

Switch to `ThrowExactly`

```cs
    [Fact]
    public void xUnit_FluentAssertions_ExceptionTest()
    {
        Action act = () => new Person(null);
        
        act.Should().ThrowExactly<Exception>()
            .WithMessage("Value cannot be null. (Parameter 'name')");
    }
```

Output

> Expected type to be System.Exception, but found System.ArgumentNullException.


### End!

That was an introduction to this amazing library! I use a lot in the projects that I'm working on because of readability and easy use.