Fluent Assertions - ITsvetkoFF/Kv-013 GitHub Wiki

About

Fluent Assertions is a set of .NET extension methods that allow you to more naturally specify the expected outcome of a TDD or BDD-style unit test.

Examples

To verify that a string begins, ends and contains a particular phrase.

string actual = "ABCDEFGHI";
actual.Should().StartWith("AB").And.EndWith("HI").And.Contain("EF").And.HaveLength(9);    

To verify that a collection contains a specified number of elements and that all elements match a predicate.

IEnumerable collection = new[] { 1, 2, 3 };
collection.Should().HaveCount(4, "because we thought we put three items in the collection"))    

The nice thing about the second failing example is that it will throw an exception with the message

"Expected <4> items because we thought we put three items in the collection, but found <3>."     

To verify that a particular business rule is enforced using exceptions.

var recipe = new RecipeBuilder()
                    .With(new IngredientBuilder().For("Milk").WithQuantity(200, Unit.Milliliters))
                    .Build();
Action action = () => recipe.AddIngredient("Milk", 100, Unit.Spoon);
       action.ShouldThrow<RuleViolationException>()
                .WithMessage("change the unit of an existing ingredient", ComparisonMode.Substring)
                .And.Violations.Should().Contain(BusinessRule.CannotChangeIngredientQuanity);    

One neat feature is the ability to chain a specific assertion on top of an assertion that acts on a collection or graph of objects.

dictionary.Should().ContainValue(myClass).Which.SomeProperty.Should().BeGreaterThan(0);
someObject.Should().BeOfType<Exception>().Which.Message.Should().Be("Other Message");
xDocument.Should().HaveElement("child").Which.Should().BeOfType<XElement>().And.HaveAttribute("attr", "1");    

Why to Use

Unit test can fail without clearly explaining why. More than often, you need to set a breakpoint and start up the debugger to be able to figure out what went wrong. And Fluent Assertions helps to "keep out of the debugger hell".

Unit test should test only a single condition per test case. If it doesn't, and the first condition fails, the test engine will not even try to test the other conditions. But if any of the others fail, you'll be on your own to figure out which one. However, if you have to for several conditions consider using a parameterized test that is being called by several clearly named test cases.

Fluent Assertions is to help you in this area. Not only by using clearly named assertion methods, but also by making sure the failure message provides as much information as possible. Consider this example:

"1234567890".Should().Be("0987654321");   

This will be reported as:

Expected string to be
"0987654321", but
"1234567890" differs near "123" (index 0).   

The fact that both strings are displayed on a separate line is not a coincidence and happens if any of them is longer than 8 characters. However, if that's not enough, all assertion methods take an optional explanation (the because) that supports formatting placeholders similar to String.Format which you can use to enrich the failure message. For instance, the assertion

new[] { 1, 2, 3 }.Should().Contain(item => item > 3, "at least {0} item should be larger than 3", 1);

will fail with:

Collection {1, 2, 3} should have an item matching (item > 3) because at least 1 item should be larger than 3.

Installation

NuGet package: FluentAssertions

Useful links

Detailed Documentation

Source on GitHub

⚠️ **GitHub.com Fallback** ⚠️