Part 12: FluentAssertions: Write More Readable Unit Tests
While xUnit’s Assert class is powerful, it can sometimes feel clunky or less intuitive. FluentAssertions is a popular library that allows you to write assertions in a more natural, “fluent” way that reads like a sentence.
1. Installation & Setup
To use FluentAssertions in your test project, you need to install the NuGet package:
dotnet add package FluentAssertions
Once installed, add the following using directive to your test files:
using FluentAssertions;
2. Basic Assertions
The core of FluentAssertions is the .Should() extension method.
Strings
string name = "John Doe";
name.Should().StartWith("John");
name.Should().EndWith("Doe");
name.Should().Contain(" ");
name.Should().HaveLength(8);
name.Should().BeEquivalentTo("JOHN DOE"); // Case-insensitive
Numbers
int result = 42;
result.Should().Be(42);
result.Should().BeGreaterThan(40);
result.Should().BeInRange(1, 100);
Booleans & Nulls
bool isReady = true;
isReady.Should().BeTrue();
object myObj = null;
myObj.Should().BeNull();
3. Collection Assertions
Working with collections is significantly easier with FluentAssertions.
var numbers = new[] { 1, 2, 3, 4, 5 };
numbers.Should().HaveCount(5);
numbers.Should().Contain(3);
numbers.Should().OnlyHaveUniqueItems();
numbers.Should().StartWith(1).And.EndWith(5);
numbers.Should().BeInAscendingOrder();
4. Object Graph Comparison
One of the most powerful features is BeEquivalentTo. It performs a deep comparison of two objects, comparing their properties rather than their references.
var expected = new User { Id = 1, Name = "Alice" };
var actual = new User { Id = 1, Name = "Alice" };
// xUnit would fail this if it's a reference comparison
// actual.Should().BeEquivalentTo(expected);
You can even exclude specific properties:
actual.Should().BeEquivalentTo(expected, options => options.Excluding(u => u.Id));
5. Exception Assertions
Testing for exceptions is much more readable than the standard Assert.Throws.
Action act = () => service.DoSomething(null);
act.Should().Throw<ArgumentNullException>()
.WithParameterName("input")
.WithMessage("*cannot be null*");
6. Why use FluentAssertions?
| Feature | Standard xUnit | FluentAssertions |
|---|---|---|
| Readability | Assert.Equal(expected, actual) |
actual.Should().Be(expected) |
| Fail Messages | Often generic | Very descriptive (explains why it failed) |
| Chaining | Not possible | obj.Should().NotBeNull().And.BeOfType<User>() |
| Collections | Requires multiple asserts | Powerful single-line assertions |
7. References & Further Reading
- Official Documentation: Fluent Assertions
- GitHub Repository: FluentAssertions GitHub
C# Interview Series
- Part 1: Key Concepts and Knowledge
- Part 2: LINQ and Sorting
- Part 3: LeetCode Tips and Tricks
- Part 4: Entity Framework Core Mastery
- Part 5: ADO.NET Fundamentals
- Part 6: SQL Server T-SQL Fundamentals
- Part 7: Clean Architecture: Principles, Layers, and Best Practices
- Part 8: N-Tier Architecture: Structure, Layers, and Beginner Guide
- Part 9: Repository and Unit of Work Patterns: Implementation and Benefits
- Part 10: TDD and Unit Testing in .NET: Production-Ready Strategies
- Part 11: xUnit Testing: Facts, Theories, and Data-Driven Tests
- Part 12: FluentAssertions: Write More Readable Unit Tests
Leave a comment