Fluent Assertions – Working with Exceptions

When writing automated tests, verifying that a certain piece of code throws the expected exception is just as important as verifying positive outcomes. Fluent Assertions in C# makes exception testing more readable, expressive, and less error-prone compared to traditional Assert.Throws syntax.


Why Test for Exceptions?

Exception testing ensures that your application behaves correctly in edge cases and error scenarios. For example:

  • When invalid input should trigger an exception
  • When certain operations are not allowed
  • When dependencies fail and your code must handle it gracefully

Traditional xUnit Exception Testing


[Fact]
public void Divide_By_Zero_Should_Throw_Exception()
{
    Assert.Throws<DivideByZeroException>(() => Calculator.Divide(10, 0));
}

This works fine, but it’s not as expressive and doesn’t allow detailed inspection of the exception message in a clean way.


Exception Testing with Fluent Assertions

Fluent Assertions makes this much easier and more expressive:


[Fact]
public void Divide_By_Zero_Should_Throw_Exception()
{
    Action act = () => Calculator.Divide(10, 0);

    act.Should()
       .Throw<DivideByZeroException>()
       .WithMessage("*divide by zero*");
}

Key Benefits:

  • Readable chain of assertions
  • Ability to verify exception type and message
  • Supports wildcards in messages (*text*)

Capturing the Exception for Further Assertions

Sometimes, you may need to inspect additional properties of the exception:


[Fact]
public void Invalid_Operation_Should_Contain_Extra_Details()
{
    Action act = () => OrderService.ProcessOrder(null);

    var exception = act.Should()
                       .Throw<InvalidOperationException>()
                       .Which;

    exception.Data["OrderId"].Should().BeNull();
}

Async Exception Testing

For asynchronous methods, Fluent Assertions provides an await act.Should().ThrowAsync<T>() syntax:


[Fact]
public async Task Async_Method_Should_Throw_Exception()
{
    Func<Task> act = async () => await UserService.CreateUserAsync(null);

    await act.Should()
             .ThrowAsync<ArgumentNullException>()
             .WithMessage("*username*");
}

Best Practices for Exception Testing

  • Test both exception type and message when applicable
  • Use wildcard matching for messages to avoid brittle tests
  • For async methods, always use ThrowAsync
  • Keep tests focused on one scenario per method

๐Ÿ“ฃ I’d Love Your Feedback

Was this helpful? Have scenarios you want covered (e.g., dictionaries, sets, or deep-object comparisons)? Share your suggestions, and I’ll explore them next.

๐Ÿ”” Stay connected and follow HGDevHub for more micro tools, automation scripts, and tech walkthroughs:

๐Ÿ“ฉ Stay Tuned

More automation scripts and micro-tools coming soon. Follow HGDevHub for fresh tools that save time and spark ideas.

Comments

Popular posts from this blog

Fluent Assertions in C# with xUnit – Clean and Readable Unit Tests

Auto-Open URLs with Node.js – A Beginner-Friendly Script

Top 7 Must-Watch Anime for Beginners: Your Gateway to an Epic Adventure