fluentassertions/fluentassertions

About this project

for usage documentation, an tips & tricks

About this project

A very extensive set of extension methods that allow you to more naturally specify the expected outcome of a TDD or BDD-style unit tests. Targets .NET Framework 4.7, as well as .NET Core 2.1, .NET Core 3.0, .NET Standard 2.0 and 2.1.

See https://www.fluentassertions.com for background information, usage documentation, an extensibility guide, support information and more tips & tricks.

Who created this?

Originally authored by Dennis Doomen with Jonas Nyrup as the productive side-kick. Notable contributions were provided by Artur Krajewski, Lukas Grützmacher and David Omid.

How do I build this?

Install Visual Studio 2019 16.9+ or JetBrains Rider 2017.1 and Build Tools 2017 and run. You will also need to have .NET Framework 4.7 SDK and .NET 5.0 SDK installed - check global.json for the current minimum required version.

What are these Approval.Tests?

This is a special set of tests that use the Verify project to verify whether you've introduced any breaking changes in the public API of the library.

If you've verified the changes and decided they are valid, you can accept them using AcceptApiChanges.ps1 or AcceptApiChanges.sh. See also the Contribution Guidelines..

build.ps1

Powered By

Supported by Patreons Michaël Hompus, Artur Krajewski and Matthias Koch

Also made possible by

and

Issues

Quick list of the latest Issues we found

xzxzxc

xzxzxc

Icon For Comments0

Description

In the case of using AssertionScope with the CompleteWithinAsync method over the delegate that returns a task with a result (Task<T>), the method will wait until the task is completed.

Complete minimal example reproducing the issue

Expected behavior:

The CompleteWithinAsync method will throw an exception in a decent period of time.

Actual behavior:

Execution stucks in the infinite loop.

Versions

I'm using FluentAssertions 6.7.0 with net6.0.

Additional Information

Issue disappears with one of the following changes:

  • remove usage of the AssertionScope;
  • remove return statement from the someAsyncWork (change the type of the delegate from Func<Task<T>> to Func<Task>).
ericnewton76

ericnewton76

Icon For Comments0

Should DataSet/DataTable/DataRow assertions get lumped into a separate library? These are types that are over 20 years old, introduced with NetFramework 1.0 beta 1... and I know this because yes I was porting things from VB6 back then as fast as I could... ;-D

Of note, starting a fresh testing project with nunit 3.12 and fluentassertions 6.7.0, I get reference errors about missing reference to System.Data v4.0.0. Otherwise FluentAssertions is pretty clean.

  • FluentAssertions 6.7.0
nohwnd

nohwnd

enhancement
Icon For Comments4

Before you file a bug, have you:

  • Tried upgrading to newest version of Fluent Assertions, to see if your issue has already been resolved and released? - yes
  • Checked existing open and closed issues, to see if the issue has already been reported? - yes could not find it
  • Tried reproducing your problem in a new isolated project? - yes
  • Read the documentation? - yes
  • Considered if this is a general question and not a bug?. For general questions please use StackOverflow. - yes, seems like a bug

Description

Using collection assertion on IEnumerable leads to enumerating the collection twice. Once for the actual assertion check and second time for formatting.

When items are actively added to the enumerable, you might end up with assertion failure that lists correct collection items. This makes the assertion message incorrect and confusing.

E.g. (added newlines for readability):

I saw this in real system, where one side is outputting messages and I am adding them into a list as they come, then using LINQ Select to select just the names of those messages and comparing them to what I expect. The server outputs last message and closes, and somehow just at the right time FluentAssertions check the collection, and just before formatting, the last message is output, and I see the error above.

Complete minimal example reproducing the issue

Complete means the code snippet can be copied into a unit test method in a fresh C# project and run. Minimal means it is stripped from code not related to reproducing the issue.

The following example outputs 2 items when first asked for the enumerator, and then all items when asked second time. Simulating what happens when item is added to the enumerable just at the right time. It also writes to console when it is asked for enumerator. E.g.

Expected behavior:

I would expect the assertion to save that data it saw when checking for success or failure, and re-use that for the message formatter.

Actual behavior:

What I described above. Assertion fails on older data, and prints newer data which are correct and leave me stumped about what is wrong.

Versions

  • Which version of Fluent Assertions are you using? 6.7.0
  • Which .NET runtime and version are you targeting? E.g. .NET framework 4.6.1 or .NET Core 2.1. Can repro on both net6 and net48.

Additional Information

nycdotnet

nycdotnet

Icon For Comments6

Description

Running code like the below throws an error "Calling Equals on Assertion classes is not supported."

I understand that this by design and is a helpful guard rail to prevent someone from thinking they're using an assertion but actually doing an equality operation and the result being thrown away. Nice job there.

I think this error message could be improved. For example, it would be nice in the example below if the exception message also said "Did you mean Be()?".

Complete minimal example reproducing the issue

Expected behavior:

Expected the exception to point me in the right direction.

Actual behavior:

I had to search the Internet for the error, found this GitHub site, read the code, realized I was dumb and should have used Be().

Versions

Latest

Additional Information

I will put in a PR if you think that supplementing the Equals() error messages to point the user in the right direction would be useful. For many of the assertions, this might be to suggest Be() but perhaps there are others which would need to use something else? I haven't looked yet. Many thanks for this very useful library.

abartho

abartho

Icon For Comments1

Description

I have an array or list of nested objects that I would like to check for equivalency. The child objects have some properties that I would like to exclude from the comparison. I'm using the new For().Exclude() syntax. That works fine when comparing individual objects, but it fails when comparing collections.

Complete minimal example reproducing the issue

Expected behavior:

Both assertions should succeed.

Actual behavior:

The second assertion (on a list) fails with the following error:

Versions

  • FluentAssertions 6.7.0
  • .NET 6.0
marcin-dardzinski

marcin-dardzinski

bug
Icon For Comments0

Description

I have a case where a base class is generic and the generic argument should be the class deriving from it. I'm trying to compare an object graph and exclude one property from this type, from a collection, i.e. ShouldBeEquvalentTo(..., o => o.For(a => a.BS).Exclude(b => b.X.Y) X is my type and Y is a property I want to exclude. Note that if I have just one object and not the collection, it works fine.

Complete minimal example reproducing the issue

Expected behavior:

The test passes, objects are equivalent except for foo.Bars[0].Y.LastModified.

Actual behavior:

The test fails with the following error:

Versions

FluentAssertions: 6.7.0 .NET 6.0 (sdk: 6.0.400, runtime: 6.0.8)

ERGeorgiev

ERGeorgiev

bug
Icon For Comments1

I have class A that inherits class ABase. ABase contains field Id of type string. A has its own Id string field declared as new to hide the Id member coming from ABase.

Scenario: Calling A.Should(). BeEquivalentTo(A)

Expected: The two fields are compared correctly for equivalency and the proper result is returned.

Actual: Throws "Sequence contains more than one matching element", thrown on line 144 (return list. SingleOrDefault()) in method TypeExtensions.FindProperty() in my decompiled code.

Note: Does not happen if you compare the same class instance to itself.

StefanBilliet

StefanBilliet

enhancement
Icon For Comments2

Hi 🙂

I was wondering if you ever considered moving the fluent DateTime extensions to a separate NuGet package, so that people would be able to use them in non-test projects without having to reference the entire FluentAssertions package. Sometimes you need static dates in your code, like cut-off dates and it would be nice to be able to use the same fluent syntax.

lg2de

lg2de

Icon For Comments6

With #1478 I implemented the extension methods WithResult for assertions on asynchronous operations. While playing around with this methods together with failed Should().CompleteWithinAsync I found that it could be unexpected, that these methods explicitly waiting for the completion of the Task. The original intention of the assertions CompleteWithinAsync were ensuring tests will not hang forever. With awaiting the Task the "timeout" is skipped and the test may hang.

Today I think whether it would be better to not await the Task and instead check whether it is already completed. In case the Task is not completed, further the result is not relevant anymore, isn't it?

jmg48

jmg48

api-suggestion
Icon For Comments7

Add a extension .Subject() Task<AndWhichConstraint<...>> to return Task

If I have an async assertion such as .ShouldNotThrowAsync() and I want to access and store the subject of the assertion, I need to await the assertion in brackets and then access the .Subject, which can feel a little clumsy and hard to read with brackets extending across several lines.

Instead, if I had an extension method .Subject() on Task<AndWhichConstraint<TParentConstraint, TMatchedElement>> which returned Task<TMatchedElement> then I could access the subject fluently as a task and await that instead.

Hope this sounds useful - I'm happy to contribute this change if it meets with approval!

An assertion that I could write today:

(note the brackets enclosing four lines of code)

The extension method I propose adding:

The original assertion, rewritten to use this extension method:

(note the brackets are no longer needed)

beerai

beerai

bug
Icon For Comments6

Description

Comparing DataTables where a column in the expectation containing a dbnull value passes comparison regardless of the value in the same column in the subject.

Complete minimal example reproducing the issue

Expected behavior:

The test to fail because "Column2" in the expectation is null while it has a value of "fail" in the subject

Actual behavior:

The test passes. Reversing the order leads to the test failing as expected, i.e.,

fails.

Versions

  • Which version of Fluent Assertions are you using? 6.7.0
  • Which .NET runtime and version are you targeting? .NET 6

Additional Information

Any additional information, configuration or data that might be necessary to reproduce the issue.

apazureck

apazureck

enhancement
Icon For Comments8

Description

When an event handler accessor has an explicit implementation, which throws an exception on the setter, .Monitor() is failing the test completely.

What is my motivation?

I need to test the class behavior without changing the other base event handler accessors behavior. It could cause unwanted side effects. But I do not need to test this event. I just wanted to test PropertyChanged events being raised. Therefore, I would like to have the benefit of having the full class available to write expressions in the assertion.

Suggestion:

Make some more configuration options for the Monitor. Like ignoring failing events, or just subscribing to a subset of interfaces with those events, or putting some events on ignore, without changing the generic Type, which is used to assert / monitor.

Benefit:

Using the great syntax you introduced in monitor on brown field projects or if you are not able to change the behavior of some event accessors. Therefore, write better and cleaner test code from the beginning.

Complete minimal example reproducing the issue

Expected behavior:

FluentAssertions is able to have options in the monitor to ignore failing event handlers.

Actual behavior:

It throws an exception when .Monitor() is called and I can do nothing about it, event though I do not want to test this specific event.

Versions

FluentAssertions Version 6.7.0

Additional Information

I already implemented my custom implementation of the monitor and would offer to contribute my suggestion above to the FluentAssertions project. I just wanted to talk to you first, if you would approve of such an enhancement of the monitor or if you disagree on this feature for some reason.

So let me know if you agree or disagree.

cheers!

ParanoikCZE

ParanoikCZE

breaking change
Icon For Comments1

Description

I'm trying to find a simple global way to handle a null string as empty, but it looks like equivalency is not called correctly on the string itself but only if encapsulated.

Complete minimal example reproducing the issue

Expected behavior:

Equivalency is called properly with applied options.

Actual behavior:

Equivalency options are not applied, probably because equivalency is not properly called.

Versions

FluentAssertions 6.7.0 .NET 6.0

kcaswick

kcaswick

enhancement
Icon For Comments0

Description

It should be easy to compare an object graph while treating null and empty as equivalent, as if each empty expectation in the graph used subject.Should().BeNullOrEmpty(). Currently this does not appear to be possible without custom equivalency steps.

Ideally a single option named something like .ComparingNullAsEmpty() would enable this behavior for both collections and strings, but an alternate implementation would be subclasses of EnumerableEquivalencyStep, GenericEnumerableEquivalencyStep and StringEqualityEquivalencyStep each of which override the handling of nulls.

Examples demonstrating the enhancement

Additional examples

See StackOverflow question how make ShouldBeEquivalentTo compare empty and null as equal (Note: The answers are for old versions of FluentAssertions, and many no longer work.)

Turnerj

Turnerj

bug
Icon For Comments10

Description

A bit of a weird title but basically if I call myCollection.Should().BeEquivalent(expected, cfg => cfg.Excluding(i => i.SomeArray[0].SomeProperty)), the property isn't correctly excluded and I get the follow assertion error:

Expected property root[0].Items[0].Name to be "Foo", but "Bar" differs near "Bar"

Complete minimal example reproducing the issue

Expected behavior:

The excluding rule to be used and the test to pass.

Actual behavior:

The excluding rule is ignored and the test fails.

Versions

  • Which version of Fluent Assertions are you using? v6.6.0

  • Which .NET runtime and version are you targeting? E.g. .NET framework 4.6.1 or .NET Core 2.1. .NET 6

Additional Information

I believe this is a regression between v5.5.3 and v6.6.0 - I haven't (yet) nailed down which version but will update when I have.

Edit: The regression starts in v6.0.0. The last v5 has this behaving correctly.

Additionally, this only seems to affect properties behind the array in the excluded check. Properties on the same level as the array work as expected if excluded.

ITaluone

ITaluone

enhancement
Icon For Comments2

Before you file a bug, have you:

  • Tried upgrading to newest version of Fluent Assertions, to see if your issue has already been resolved and released?
  • Checked existing open and closed issues, to see if the issue has already been reported?
  • Tried reproducing your problem in a new isolated project?
  • Read the documentation?
  • Considered if this is a general question and not a bug?. For general questions please use StackOverflow.

Description

Is there a good reason why ForConstraint is not available in an IAssertionScope, but only in the AssertionScope implementation? Reason for this change is, that you can not chain an ForConstraint after a Then, resulting in quite longish sets of Execute.Assertion...

Complete minimal example reproducing the issue

Complete means the code snippet can be copied into a unit test method in a fresh C# project and run. Minimal means it is stripped from code not related to reproducing the issue.

E.g.

Expected behavior:

Chaining a ForConstraint should also work after Then

Actual behavior:

Does not :)

Versions

  • Which version of Fluent Assertions are you using? 6.6.0
marcrocny

marcrocny

api-suggestion
Icon For Comments4

Description

Add logical implication to the available boolean assertions.

That is, a.Should().Imply(b) asserts that a → b.

This would be useful in asserting, for example, that object equality implies hash-code equality without additional logic and a better built-in "because".

Complete minimal example

Looking for something like this.

Note this is logically equivalent to !a || b.

Additional Information

Also volunteering to add this.

souhailelk

souhailelk

bug
Icon For Comments2

Description

We compile and launch unit test libraries with the release configuration and x64 platform. After upgrading FluentAssertions from 4.19.2 to 6.5.1 (the latest), we noticed that Should().BeEquivalentTo() gives different error messages while compare classes with properties. Let's look at the following example:

  • Let ClassWithProperty be a class containing one property IntProperty:

  • The unit test CompareClassWithPropertyObjects compare two objects of type ClassWithProperty, with different property values.

Expected behavior:

Actual behavior:

Here, it outputs the }}}, instead of the name of the actual object.

Versions

  • .NET : .NET Core 3.1 and .NET 4.7.1
  • NUnit : 3.12.0 (I tried also the the version 3.13.1, It gives the same results).
  • FluentAssertions : 6.5.1
  • Configuration : Release
  • Platform : x64

Note that it works totally fine in Debug configuration.

aaronpburke

aaronpburke

bug
Icon For Comments4

Description

Nested AssertionScopes only report the outer-most scope reportables on failure. This is true regardless of whether the outer scope has any reportables -- i.e., if only the inner scope has reportables, nothing is reported.

Complete minimal example reproducing the issue

Expected behavior:

Message: Expected testVal to be 1, but found 2.

With outerReportable: foo With innerReportable: bar

Actual behavior:

Message: Expected testVal to be 1, but found 2.

With outerReportable: foo

Versions

  • Which version of Fluent Assertions are you using? 6.5.1
  • Which .NET runtime and version are you targeting? E.g. .NET framework 4.6.1 or .NET Core 2.1. .NET Framework 4.7.2

Additional Information

using Microsoft.VisualStudio.TestTools.UnitTesting test framework

jnyrup

jnyrup

up-for-grabs
Icon For Comments8

Description

We now have automatic code coverage as part of the CI pipeline, posting the result to https://coveralls.io/github/fluentassertions/fluentassertions

At the time of writing our line coverage is 95.75% and branch coverage is 92.45%. We do not seek 100% coverage at all costs as some parts might not/hardly be testable, but there are clearly spots were it's easy to write the missing tests.

Ideally all code should be testable through the public API and shouldn't require any changes to the implementation. If you think the core project needs changes, please discuss those changes here first.

bart-degreed

bart-degreed

enhancement
Icon For Comments20

After updating to the latest FA, I found that our custom extension method conflicts with the one added in v6.4.0 here.

The difference is that ours dumps the request body on HTTP status code mismatch, which is helpful in analyzing what's going on without debugging the test.

For an assertion like:

when that returns 404, we get the following test output:

I know the message is a bit messy, but it contains all the info we need: the actual status code, the expected status code, and the returned response body.

Our extension method code is the following, feel free to reuse parts as it makes sense.

Versions

Quick list of the latest released versions

6.7.0 - May 18, 2022

What's Changed

New features

Fixes

Documentation

Others

New Contributors

Full Changelog: https://github.com/fluentassertions/fluentassertions/compare/6.6.0...6.7.0

6.6.0 - Apr 03, 2022

What's Changed

New features

Improvements

Fixes

Documentation

Others

New Contributors

Full Changelog: https://github.com/fluentassertions/fluentassertions/compare/6.5.1...6.6.0

6.5.1 - Feb 11, 2022

What's Changed

Full Changelog: https://github.com/fluentassertions/fluentassertions/compare/6.5.0...6.5.1 Public release notes: https://fluentassertions.com/releases/#651

6.5.0 - Feb 10, 2022

What's Changed

New Contributors

Full Changelog: https://github.com/fluentassertions/fluentassertions/compare/6.4.0...6.5.0

6.4.0 - Jan 22, 2022

What's Changed

New Contributors

Full Changelog: https://github.com/fluentassertions/fluentassertions/compare/6.3.0...6.4.0 Public release notes: https://fluentassertions.com/releases/#640

6.3.0 - Jan 01, 2022

What's Changed

New Contributors

Full Changelog: https://github.com/fluentassertions/fluentassertions/compare/6.2.0...6.3.0

6.2.0 - Oct 25, 2021

What's Changed

New Contributors

Full Changelog: https://github.com/fluentassertions/fluentassertions/compare/6.1.0...6.2.0 Public release notes: https://fluentassertions.com/releases/#620

6.0.0-beta.3 - Aug 11, 2021

6.0.0-beta.2 - Aug 05, 2021

6.0.0-beta.1 - Jun 01, 2021

6.0.0-alpha.2 - Jan 07, 2021

5.10.2 - Feb 09, 2020

5.6.0 - Jan 11, 2019

  • {New} Provide opt-out to AssertionOptions(o => o.WithStrictOrdering()) - #974
  • {New} Add collection assertion ContainEquivalentOf - #950
  • {New} Add Should().NotThrowAfter assertion for actions - #942

Kudos to @BrunoJuchli, @matthiaslischka and @frederik-h for these amazing additions.

5.5.3 - Nov 20, 2018

  • {Fix} Performance fixes in BeEquivalenTo - #935
  • {Fix} Reverted 5.5.0 changes to AssertionScope to ensure binary compatibility - #977

5.5.2 - Nov 19, 2018

  • {Fix} Allows BeEquivalentTo to handle a non-generic collection as the SUT - #975, #973
  • {Fix} Optimized performance of IncludeMemberByPathSelectionRule - #969

5.5.1 - Nov 08, 2018

  • {New} Now provides a hint when strings differ in length and contain differences - #915, #907
  • {New} Added ThrowAsync, ThrowExactlyAsync and NotThrowAsync - #931
  • {New} Added support for Should().Throw and Should().NotThrow for Func<T> - #951
  • {New} Added support for private protected access modifier - #932
  • {New} Updated BeApproximately to support nullable types for both the subject and the expectation nullable - #934
  • {New} Added async version of ExecutionTime to - #938
  • {New} Updated NotBeApproximately to accepting nullable subject and expectation - #939
  • {New} type.Should().Be(type) now support open generics - #954, #955
  • {Fix} Minor performance improvements to prevent rendering messages if a test did not fail - #921, #915
  • {Fix} Improve performance of Should().AllBeEquivalentTo() - #920, #914
  • {Fix} Improve the presentation of enums to include the value and the number - #923, #897
  • {Fix} BeEquivalentTo with WithStrictOrdering produced messy failure message - #918
  • {Fix} Fixes detecting checking equivalency of a null subject to a dictionary - #933
  • {Fix} Fixes duplicate conversions being mentioned in the output of the equivalency API - #941
  • {Fix} Comparing an object graph against IEnumerable now works now as expected - #911
  • {Fix} Selecting members during object graph assertions now better handles new overrides -#960, #956

Note In versions prior to 5.5, FA may have skipped certain properties in the equivalency comparison. #960 fixes this, so this may cause some breaking changes.

Lots of kudos @jnyrup and @krajek for a majority for the work in this release.

5.5.0 - Dec 06, 2019

  • {Breaking Change} Since the addition of Should().Throw and Should().NotThrow for Func<T>, assertions Should().Be and Should().NotBe can't be used on Func<T> objects anymore, so this may cause breaking changes. These instances can easily be replaced with Should().BeSameAs and Should().NotBeSameAs as these types are compared by references.

5.4.2 - Sep 14, 2018

  • {Fix} Limits the depth of rendering an object to a max of 5 to prevent OOM exceptions - #898
  • {Fix} Show the entire exception instead of just the message when an async function throws - #892
  • {Fix} Fixed a StackOverflow while comparing an self-returning enumerable - #887
  • {Fix} Custom rules (Using().WhenTypeIs()) were not executed on dictionary equivalency assertions - #886
  • {Fix} The failure message of HaveOffset returned the seconds instead of the offset - #883

5.4.1 - Jun 20, 2018

  • {Fix} Make GetEqualityStrategy thread-safe again - #864

5.4.0 - Jun 13, 2018

  • {Fix} Fixes the dependency on the unlisted System.Reflection.Emit by adding direct support for .NET Core - #861
  • {Potentially Breaking} Restricted the Event assertion API to the run-time .NET platforms only - #861

5.3.2 - May 27, 2018

  • {Fix} AssertionScope did not work with GenericCollectionAssertions - #835
  • {Fix} Improved the performance of asserting large arrays for equivalency - #840
  • {Fix} Handle an edge case that only seems to happen under NCrunch - #841
  • {Fix} Resolved potential deadlocks and long-running threads in the execution time assertions - #842

Kudos to @peterekepeter and @jnyrup for those fixes.

5.3.0 - Apr 19, 2018

  • {Fix} Fix String.ContainAll param documentation - #810
  • {Fix} Test framework detection didn't always work under .NET Core 2.0 - #825
  • {New} MethodImplAttribute now works with (Not)BeDecoratedWith - #804
  • {New} Added support for integral types to [Not]BeCloseTo - #803
  • {New} Increased the accuracy of [Not]BeCloseTo for DateTime[Offset] to Tick precision instead of milliseconds - #820
  • {New} Many performance improvements to BeEquivalentTo - #817

Kudos to @jnyrup for making this release possible. Thanks to @melchiork for contributing #825.

Library Stats (Sep 21, 2022)

Subscribers: 70
Stars: 2.9K
Forks: 463
Issues: 98

CSharpMinifier filters comments and unnecessary whitespace from valid C#

source code in order to arrive at a compressed form without changing the

CSharpMinifier filters comments and unnecessary whitespace from valid C#

CSharpFastPFOR: A C# port of the simple integer compression library JavaFastPFOR

==========================================================

CSharpFastPFOR: A C# port of the simple integer compression library JavaFastPFOR

csharp-data-visualization

I've always wanted to learn how to visualize data in C#

csharp-data-visualization

CSharpToCppTranslator

A specific translator for LinksPlatform's libraries

CSharpToCppTranslator

CSharpDecodeSdpc

This is a tool to extract image tiles from pathological whole slide images (WSIs) based on C#

CSharpDecodeSdpc

C Sharp Helper Methods

Bu bir Windows Form uygulamasıdır ve içerisinde genel olarak ERP projelerinde sıkça kullanılabilecek bazı metotları ve kullanımlarını içermektedir

C Sharp Helper Methods

CSharp-CodeSnippet

Wide variety of sample code snippets from the topics related in C#

CSharp-CodeSnippet

CSharp &quot;C#&quot; WAVE &quot;

Parses the audio data and the format chunk info from a WAVE-Format audio file &quot;

CSharp &quot;C#&quot; WAVE &quot;

CSharp_ChromaStreamApp

C# Chroma Stream App for Chroma RGB streaming

CSharp_ChromaStreamApp

CSharp-SMTP-Server

Simple (receive only) SMTP server library for C#

CSharp-SMTP-Server

CSharp To Mindustry Logic

This is a code transpiler that will transpile C# code to mlog

CSharp To Mindustry Logic