DEV Community

Cover image for Sparky's Tool Tips: Fluent Assertions
Brian Schroer
Brian Schroer

Posted on • Edited on

1 3

Sparky's Tool Tips: Fluent Assertions

I like writing unit tests more than the average developer (not saying much, I realize - Testing is something many devs... de-test 🥁).

I really appreciate tools that make it easier and more fun to write tests (in fact, I've written some myself), and Fluent Assertions is one of my favorites.

Fluent Assertions logo

The Microsoft.VisualStudio.TestTools.UnitTesting Assert, StringAssert and CollectionAssert classes are... OK, I guess. (It's been a while since I used NUnit and I've never used xUnit, so I don't know about the built-in asserts in those frameworks.)

Fluent Assertions is a set of .NET extension methods that allow you to specify the expected outcome of a TDD or BDD-style unit test with a sentence-like syntax. For example, the "MSTest" syntax:

Assert.AreEqual(31, daysInJune);
Enter fullscreen mode Exit fullscreen mode

...can be fluently expressed as:

using FluentAssertions;
. . .
daysInJune.Should().Be(31);
Enter fullscreen mode Exit fullscreen mode

"Using" the "FluentAssertions" namespace enables a ton of useful "Should()" extension methods for:

strings:

  • Be(expected)
  • BeNull()
  • BeEmpty()
  • StartWith(expected)
  • EndWith(expected)
  • HaveLength(expected)
  • Contain(expected)
  • ...

numbers:

  • Be(expected)
  • BeGreatorOrEqualTo(expected)
  • BeLessOrEqualTo(expected)
  • BeInRange(minimum, maximum)
  • BePositive()
  • ...

DateTime:

  • Be(1.March(2022).At(22, 15))
  • BeOnOrAfter(1.March(2010))
  • HaveDay(1)
  • HaveMonth(3)
  • HaveYear(2010)
  • HaveHour(22)
  • BeLessThan(10.Minutes()).Before(otherDatetime)
  • ...

collections:

  • HaveCount(expected)
  • HaveSameCount(otherCollection)
  • Contain(expected)
  • NotContain(expected)
  • OnlyContain(x => x.predicate)
  • ...

These are just a few examples. There are dozens more methods for these and many other types.

And... assertions are chainable!

string stateName = "OHIO";
stateName.Should().StartWith("O").And.EndWith("O").And.Contain("HI");
Enter fullscreen mode Exit fullscreen mode

Exceptions

I don't like the MS Test [ExpectedException(type)] attribute. Among other shortcomings, it doesn't let you test the exception message.

With Fluent Assertions, exception testing looks like this:

subject.Invoking(x => x.Foo("Hello"))
    .Should().Throw<InvalidOperationException>()
    .WithMessage("Hello is not allowed at this moment");
Enter fullscreen mode Exit fullscreen mode

...or with "arrange / act / assert" syntax:

Action action = () => x.Foo("Hello");

action
    .Should().Throw<InvalidOperationException>()
    .WithMessage("Hello is not allowed at this moment");
Enter fullscreen mode Exit fullscreen mode

Extensibility

Fluent Assertions is nicely set up to allow you to write your own "Should" extension methods.

There are many NuGet packages containing additional extension methods, including my own SparkyTestHelpers.Moq.Fluent.

But wait, there's more!

Fluent Assertions doesn't just give you better syntax for writing assertions - it gives you much better messages when an assertion fails, for example:

With Assert.AreEqual:

string correctNameSpelling = "Bryan";
Assert.AreEqual("Brian", correctNameSpelling);
Enter fullscreen mode Exit fullscreen mode

...the failure message is:

Assert.AreEqual failed. Expected:<Brian>. Actual:<Bryan>.
Enter fullscreen mode Exit fullscreen mode

With Fluent Assertions:

string correctNameSpelling = "Bryan";
correctNameSpelling.Should().Be("Brian");
Enter fullscreen mode Exit fullscreen mode

..the failure message is:

Expected correctNameSpelling to be "Brian", but "Bryan" differs near "yan" (index 2).
Enter fullscreen mode Exit fullscreen mode

The "differs near" and index are a bit of overkill for strings this short, but pretty handy for long strings!

(BTW, this is not a trivial example. correctNameSpelling SHOULD BE "Brian" and if your parents named you "Bryan", you should call them and complain.😏)


I like Fluent Assertions a lot, and if you're writing .NET unit tests, I think you .Should() give it a try!

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

Top comments (0)

The Most Contextual AI Development Assistant

Pieces.app image

Our centralized storage agent works on-device, unifying various developer tools to proactively capture and enrich useful materials, streamline collaboration, and solve complex problems through a contextual understanding of your unique workflow.

👥 Ideal for solo developers, teams, and cross-company projects

Learn more

AWS Security LIVE!

Hosted by security experts, AWS Security LIVE! showcases AWS Partners tackling real-world security challenges. Join live and get your security questions answered.

Tune in to the full event

DEV is partnering to bring live events to the community. Join us or dismiss this billboard if you're not interested. ❤️