How to replace FluentAssertions library


FluentAssertions is a library that almost everyone in the .NET community has either used or at least heard of. Until version 8, it was a free, open-source project. However, starting with version 8, a license is required to use it.
I am not against purchasing software or libraries, but sometimes it is not financially feasible. In such cases, we need to find alternative solutions.
Using FluentAssertions 7
We can continue using FluentAssertions by sticking with version 7, which remains free and receives updates. To ensure we do not unintentionally upgrade to version 8, we can specify the exact version in our .csproj
file using square brackets. This prevents IDEs from suggesting an update.
<PackageReference Include="FluentAssertions" Version="[7.0.0]" />
Advantages: No changes are required in tests, and we can continue using FluentAssertions as before.
Disadvantages: If someone on the team manually updates the package version, they may unintentionally violate the license agreement. Additionally, because version 7 is no longer the primary focus, its support could end at any time. If that happens and you have thousands of tests relying on an outdated package, you might spend valuable time fixing tests instead of delivering software.
Using an Alternative Like Shouldly
Shouldly is a similar assertion library that receives regular updates and is licensed under the BSD 3-Clause License, allowing its use in proprietary software.
The package has well-written documentation, and its syntax is intuitive. For those familiar with FluentAssertions, transitioning to Shouldly should not be difficult.
To install the package, use the following command:
dotnet add package Shouldly
Example assertions:
myObject.DoWorkAndReturnInteger().ShouldBe(12);
myObject.Exists().ShouldBeTrue();
Advantages: Open-source, actively maintained, and has good documentation with a clean syntax.
Disadvantages: Since it is still a third-party project, there is always a risk that its maintainers may decide to change its licensing model in the future. Additionally, while the syntax is similar, it is not identical, meaning the entire test codebase will require modifications.
Writing Your Assertion Library
If you primarily use FluentAssertions for its syntax and can accept less polished exception messages, developing your assertion library might be a viable option. Using assertions from your existing test framework simplifies the process.
The following example is based on xUnit, but the concept applies to other frameworks as well.
Start by creating a C# library project and adding the xunit.assert
package:
dotnet add package xunit.assert
This package provides all available xUnit assertions, allowing us to wrap them in our custom assertions.
Consider the following test that uses FluentAssertions:
[Fact]
public void GetSomeString_ShouldReturnString()
{
// Arrange
var expected = "string we expect";
// Act
var actual = _sut.GetSomeString();
// Assert
actual.Should().Be(expected);
}
To support similar assertions, let's create a StringAssertions
class:
public class StringAssertions
{
private readonly string _value;
internal StringAssertions(string value)
{
_value = value;
}
public void Be(string expected) => Assert.Equal(expected, _value);
}
This class is a simple wrapper around xUnit assertions. We can use it like this:
var actual = "my string";
var expected = "another string";
new StringAssertions(actual).Be(expected);
While this works, the syntax is not ideal. We can improve it with an extension method:
public static class AssertionExtensions
{
public static StringAssertions Should(this string actual) => new StringAssertions(actual);
}
Now, we can write assertions in the familiar .Should().Be()
format.
Advantages: The assertion code remains under your control and can be modified as needed. If necessary, you can integrate another assertion library in the future.
Disadvantages: Writing and maintaining assertion methods can be time-consuming. While simple, achieving feature parity with FluentAssertions or Shouldly would require significant effort.
Forking FluentAssertions 7
I list this option last because very few developers will likely choose it. There is a support-7.0 branch that contains the FluentAssertions source code under the Apache 2.0 license. This means the code can still be used in personal and commercial projects.
If your test suite heavily depends on FluentAssertions and migrating to another library is impractical, forking the repository, packaging your version, and using it internally might be a reasonable solution.
Before proceeding, carefully review the repository's license file to understand the legal implications.
Advantages: No test changes are required, and you can continue using FluentAssertions as before.
Disadvantages: You must maintain the fork, apply necessary updates, and fix bugs that are not addressed in the main repository.
Summary
This article provides an overview of possible alternatives to FluentAssertions. None of these options are perfect, and each comes with its own set of advantages and disadvantages. Choosing the best approach depends on various factors, including the size of your test codebase, the feasibility of using alternative packages, and your willingness to invest time in writing additional code.
Links
Subscribe to my newsletter
Read articles from Ihar Maiseyeu directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
