Skip to content

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

@julealgon

Description

@julealgon

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions