I like writing unit tests more than the average developer (not saying much, I realize - Testing is something many devs... de-test 🥁).
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:
...can be fluently expressed as:
using FluentAssertions; . . . daysInJune.Should().Be(31);
"Using" the "FluentAssertions" namespace enables a ton of useful "Should()" extension methods for:
- BeInRange(minimum, maximum)
- Be(1.March(2022).At(22, 15))
- OnlyContain(x => x.predicate)
These are just a few examples. There are dozens more methods for these and many other types.
string stateName = "OHIO"; stateName.Should().StartWith("O").And.EndWith("O").And.Contain("HI");
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");
...or with "arrange / act / assert" syntax:
Action action = () => x.Foo("Hello"); action .Should().Throw<InvalidOperationException>() .WithMessage("Hello is not allowed at this moment");
Fluent Assertions is nicely set up to allow you to write your own "Should" extension methods.
Fluent Assertions doesn't just give you better syntax for writing assertions - it gives you much better messages when an assertion fails, for example:
string correctNameSpelling = "Bryan"; Assert.AreEqual("Brian", correctNameSpelling);
...the failure message is:
Assert.AreEqual failed. Expected:<Brian>. Actual:<Bryan>.
With Fluent Assertions:
string correctNameSpelling = "Bryan"; correctNameSpelling.Should().Be("Brian");
..the failure message is:
Expected correctNameSpelling to be "Brian", but "Bryan" differs near "yan" (index 2).
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!