Using FluentAssertions for C# Unit Tests
This article provides a concise guide to performing assertion validation in C# using FluentAssertions. You will learn how to set up the library, use its fluent syntax for common data types, validate complex object graphs, assert thrown exceptions, and work with collections to make your unit tests more readable and expressive.
Getting Started
To use FluentAssertions, install the NuGet package into your test project via the .NET CLI:
dotnet add package FluentAssertionsThen, include the namespace at the top of your test files:
using FluentAssertions;FluentAssertions works seamlessly with any major testing framework, including xUnit, NUnit, and MSTest.
Basic Value Assertions
FluentAssertions replaces traditional assertion methods (like
Assert.AreEqual) with natural language extension methods
prefixed with .Should().
// Numbers
int count = 10;
count.Should().Be(10);
count.Should().BeGreaterThan(5);
count.Should().BeInRange(1, 20);
// Booleans
bool isCompleted = true;
isCompleted.Should().BeTrue();
// Strings
string message = "Order successfully created";
message.Should().StartWith("Order")
.And.EndWith("created")
.And.Contain("successfully");Collection Assertions
Validating lists, arrays, and dictionaries is straightforward with built-in collection methods that handle order, count, and containment.
var numbers = new List<int> { 1, 2, 3, 4, 5 };
numbers.Should().NotBeEmpty()
.And.HaveCount(5)
.And.ContainInOrder(1, 2, 3)
.And.OnlyHaveUniqueItems();
// Checking items against a condition
numbers.Should().AllSatisfy(x => x.Should().BeGreaterThan(0));Exception Assertions
To verify that a specific exception is thrown, wrap the execution in
an Action or Func and call
.Should().Throw<T>().
Action act = () => account.Withdraw(500);
act.Should().Throw<InvalidOperationException>()
.WithMessage("*insufficient funds*");For asynchronous methods:
Func<Task> act = async () => await service.ProcessOrderAsync(null);
await act.Should().ThrowAsync<ArgumentNullException>()
.WithParameterName("order");Object Graph and Equivalency Assertions
When testing complex types, comparing individual properties manually
can be tedious. FluentAssertions provides BeEquivalentTo(),
which compares entire object trees property-by-property rather than by
reference:
var expectedUser = new User { Id = 1, Name = "Alice" };
var actualUser = userService.GetUser(1);
actualUser.Should().BeEquivalentTo(expectedUser);You can customize the comparison logic, such as excluding specific fields:
actualUser.Should().BeEquivalentTo(expectedUser, options =>
options.Excluding(u => u.CreatedDate));Multiple Assertions with AssertionScope
By default, an assertion failure halts the test immediately. Wrapping
multiple assertions in an AssertionScope collects all
failures and reports them together:
using (new FluentAssertions.Execution.AssertionScope())
{
user.Name.Should().Be("Alice");
user.Email.Should().Be("alice@example.com");
user.IsActive.Should().BeTrue();
}