Skip to content

Global AssertEquivalencyUsing have no effect for record types without public members #1977

@kostyden

Description

@kostyden

Description

Using static method AssertionOptions.AssertEquivalencyUsing to configure comparison by value for one specific record type doesn't work. Instances are still compared by member.

Record type is a type without public members

public record Position
{
    public static Position None = new(0);
    public static Position One = new(1);
    public static Position Two = new(2);

    private readonly int _value;

    private Position(int value)
    {
        _value = value;
    }
}

// Wrapper class
public class Player
{
    public string Name { get; }
    public Position Position { get; }

    public Player(string name, Position position)
    {
        Name = name;
        Position = position;
    }
}

Explicitly provided configuration works as expected

// Pass
Position.Two.Should().NotBeEquivalentTo(Position.One, o => o.ComparingByValue(typeof(Position)));

// Pass
var player1 = new Player("First", Position.One);
var player2 = new Player("First", Position.Two);
        
player1.Should().NotBeEquivalentTo(player2, o => o.ComparingByValue(typeof(Position)));

Complete minimal example reproducing the issue

Configuring comparison behaviour "globally" via static AssertionOptions.AssertEquivalencyUsing doesn't work

AssertionOptions.AssertEquivalencyUsing(
    options => options.ComparingByValue(typeof(Position))
);          
// Fail
Position.Two.Should().NotBeEquivalentTo(Position.None);

var player1 = new Player("First", Position.One);
var player2 = new Player("First", Position.Two);

// Fail
player1.Should().NotBeEquivalentTo(player2);

Expected behavior:

Expect tests in "complete minimal example" to pass

Actual behavior:

Tests are failing with corresponding exceptions

AssertionOptions.AssertEquivalencyUsing(options => options.ComparingByValue(typeof(Position)));
Position.Two.Should().NotBeEquivalentTo(Position.None);

// Exception
System.InvalidOperationException
No members were found for comparison. Please specify some members to include in the comparison or choose a more meaningful assertion.
   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)
   at FluentAssertions.Primitives.ObjectAssertions`2.NotBeEquivalentTo[TExpectation](TExpectation unexpected, Func`2 config, String because, Object[] becauseArgs)
   at FluentAssertions.Primitives.ObjectAssertions`2.NotBeEquivalentTo[TExpectation](TExpectation unexpected, String because, Object[] becauseArgs)

Within wrapper type

var player1 = new Player("First", Position.One);
var player2 = new Player("First", Position.Two);

player1.Should().NotBeEquivalentTo(player2);

// Exception
Xunit.Sdk.XunitException
Expected player1 not to be equivalent to EncapsulatedRecordTests.Player
{
    Name = "First", 
    Position = Position { }
}, but they are.
   at FluentAssertions.Execution.XUnit2TestFramework.Throw(String message)
   at FluentAssertions.Execution.TestFrameworkProvider.Throw(String message)
   at FluentAssertions.Execution.DefaultAssertionStrategy.HandleFailure(String message)
   at FluentAssertions.Execution.AssertionScope.FailWith(Func`1 failReasonFunc)
   at FluentAssertions.Execution.AssertionScope.FailWith(Func`1 failReasonFunc)
   at FluentAssertions.Execution.AssertionScope.FailWith(String message, Object[] args)
   at FluentAssertions.Primitives.ObjectAssertions`2.NotBeEquivalentTo[TExpectation](TExpectation unexpected, Func`2 config, String because, Object[] becauseArgs)
   at FluentAssertions.Primitives.ObjectAssertions`2.NotBeEquivalentTo[TExpectation](TExpectation unexpected, String because, Object[] becauseArgs)

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.
    net6.0

Additional Information

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions