question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Exception thrown when comparing empty types using 'BeEquivalentTo' with 'RespectingRuntimeTypes' set

See original GitHub issue

Description

I have a scenario where I need to compare a response object against an expected object, and I’m using source.Should().BeEquivalentTo(target) for that.

However, I hit a situation where I believe the library has a poor default: when the objects being compared have no declared members and you only want to ensure that the types match.

I tried to “correct” what I thought was a mistake on my part, by setting the RespectingRuntimeTypes() option. This has not changed the result however.

Complete minimal example reproducing the issue

Say I have some interface/base class defining a set of possible values, something like:

public abstract class SomeResponse
{
} 

public sealed class NotFoundResponse : SomeResponse
{
}

public sealed class ValidResponse : SomeResponse
{
    public ValidResponse(int value)
    {
        this.Value = value;
    }

    public int Value { get; }
}

Notice how one of the response types has no properties, while the other has a single property.

Now, if I attempt to compare some response variable, and it happens to be NotFoundResponse, I get an exception:

// Arrange (fake values)
SomeResponse response = new NotFoundResponse();
SomeResponse expectedResponse = new NotFoundResponse();

// Assert
response.Should().BeEquivalentTo(expectedResponse, c => c.RespectingRuntimeTypes());

Expected behavior:

I think it would be best if the comparison succeeded when both objects have no properties but are of the same runtime type if the RespectingRuntimeTypes setting is used.

Actual behavior:

The following exception is thrown:

System.InvalidOperationException : No members were found for comparison. Please specify some members to include in the comparison or choose a more meaningful assertion.
Stack Trace:
at FluentAssertions.Equivalency.Steps.StructuralEqualityEquivalencyStep.Handle(Comparands comparands, IEquivalencyValidationContext context, IEquivalencyValidator nestedValidator)
at FluentAssertions.Equivalency.EquivalencyValidator.RunStepsUntilEquivalencyIsProven(Comparands comparands, IEquivalencyValidationContext context)
at FluentAssertions.Equivalency.EquivalencyValidator.RecursivelyAssertEquality(Comparands comparands, IEquivalencyValidationContext context)
at FluentAssertions.Equivalency.EquivalencyValidator.AssertEquality(Comparands comparands, EquivalencyValidationContext context)
at FluentAssertions.Primitives.ObjectAssertions`2.BeEquivalentTo[TExpectation](TExpectation expectation, Func`2 config, String because, Object[] becauseArgs)

Versions

FA v6.5.1 .NET 6

Additional Information

Note that changing the comparison to something more specific (like BeOfType) would change the meaning of the comparison and is not a substitute: I need to also compare the properties when they are available.

I think it only makes sense to throw this exception if types are excluded from the comparison, but even then, it is questionable whether or not it wouldn’t be better to also return true when both sides have no members.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Reactions:1
  • Comments:5 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
dennisdoomencommented, Mar 7, 2022

I wonder if it is time to consider renaming it to something else, perhaps RespectingRuntimeTypeProperties? Otherwise, it really gives a strong impression that we are talking about the types themselves there.

Yep. Added that to the v7 list.

1reaction
dennisdoomencommented, Mar 7, 2022

That’s ok, however my understanding is that you can opt-in to it being type-aware by specifying RespectingRuntimeTypes, right? Once I do that, I’d expect the type itself to be part of the conditions to be checked, and thus the message “there is nothing to compare” (this is not the actual message but the underlying reason) would be wrong: there is now, the type.

Ah, this is where the misunderstanding is coming from. RespectingRuntimeTypes is just an option to tell FA to look at the run-time type of the object when looking for members to compare instead of the declared type. FA never cares about the type of the object’s type themselves. That’s what we are trying to accomplish using https://github.com/fluentassertions/fluentassertions/pull/1704

Read more comments on GitHub >

github_iconTop Results From Across the Web

FluentAssertions Should().BeEquivalentTo() fails in trivial ...
With configuration: Use declared types and members; Compare enums by value; Match member by name (or throw); Without automatic conversion. Be ...
Read more >
Upgrading to version 6.0 - Fluent Assertions
If you want to compare two enums of different types, you can use HaveSameValueAs or HaveSameNameAs depending on how you define equality for...
Read more >
9 Fluent Assertions Tricks to Save Hours of Your Testing ...
BeEquivalentTo method compares properties and it requires that properties have the same names, no matter the actual type of the properties. Fluent Assertions ......
Read more >
Object graph comparison
Imagine you want to compare an Order and an OrderDto using BeEquivalentTo , but the first type has a Name property and the...
Read more >
Improving Unit Tests with Fluent Assertions
In this article, we are going to learn how we can improve our unit tests using Fluent Assertions library with .NET project.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found