Skip to content

WithMapping does not map properties of collections #1840

Closed

Description

@drewkill32

Description

When using BeEquivalentTo and WithMapping over a collection the properties are not mapped and are ignored.

Complete minimal example reproducing the issue

using FluentAssertions;
using FluentAssertions.Equivalency.Tracing;


var entity = new Entity
{
    Name = "Test",
    EntityId = 1
};

var dto = EntityDto.MapFromEntity(entity);


var entityCol = new[] { entity };
var dtoCol = new[] { dto };



dtoCol.Should().BeEquivalentTo(entityCol, c =>
    c.WithMapping<EntityDto>(s => s.EntityId, d => d.Id)
        .WithTracing());

//     FluentAssertions.Execution.AssertionFailedException: Expectation has property dtoCol[0].EntityId that the other object does not have.
//
//     With configuration:
//     - Use declared types and members
//     - Compare enums by value
//     - Compare tuples by their properties
//     - Compare anonymous types by their properties
//     - Compare records by their members
//     - Include all non-private properties
//     - Include all non-private fields
//     - FluentAssertions.Equivalency.Matching.MappedPathMatchingRule
//     - Match member by name (or throw)
//     - Be strict about the order of items in byte arrays
//     - Without automatic conversion.
//
//     With trace:
//       dtoCol
//       {
//         Structurally comparing System.Object[] and expectation Entity[] at dtoCol
//         {
//           Finding the best match of Entity within all items in System.Object[] at dtoCol[0]
//           {
//             Comparing subject at dtoCol[0] with the expectation at dtoCol[0]
//             {
//               dtoCol[0]
//               {
//                 property dtoCol[0].Name
//                 {
//                   Equivalency was proven by ReferenceEqualityEquivalencyStep
//                 }
//                 Equivalency was proven by StructuralEqualityEquivalencyStep
//               }
//               Contained 1 failures
//             }
//           }
//         }
//         Equivalency was proven by GenericEnumerableEquivalencyStep
//       }
//
//        at FluentAssertions.Execution.FallbackTestFramework.Throw(String message)
//        at FluentAssertions.Execution.TestFrameworkProvider.Throw(String message)
//        at FluentAssertions.Execution.CollectingAssertionStrategy.ThrowIfAny(IDictionary`2 context)
//        at FluentAssertions.Execution.AssertionScope.Dispose()
//        at FluentAssertions.Equivalency.EquivalencyValidator.AssertEquality(Comparands comparands, EquivalencyValidationContext context)
//        at FluentAssertions.Collections.GenericCollectionAssertions`3.BeEquivalentTo[TExpectation](IEnumerable`1 expectation, Func`2 config, String because, Object[] becauseArgs)

dto.Should().BeEquivalentTo(entity, c => c
        .WithMapping<EntityDto>(s => s.EntityId, d => d.Id)
        .WithTracing());

//    FluentAssertions.Execution.AssertionFailedException: Expected property dto.Id to be 1, but found 0.

//    With configuration:
//    - Use declared types and members
//    - Compare enums by value
//    - Compare tuples by their properties
//    - Compare anonymous types by their properties
//    - Compare records by their members
//    - FluentAssertions.Equivalency.Matching.MappedPathMatchingRule
//    - Match member by name (or throw)
//    - Be strict about the order of items in byte arrays
//    - Without automatic conversion.
//   
//    With trace:
//      dto
//      {
//          property dto.Id
//          {
//              Treating property dto.Id as a value type because System.Int32 overrides Equals.
//                  Equivalency was proven by ValueTypeEquivalencyStep
//          }
//          property dto.Name
//          {
//              Equivalency was proven by ReferenceEqualityEquivalencyStep
//          }
//          Equivalency was proven by StructuralEqualityEquivalencyStep
//      }
//   
//      at FluentAssertions.Execution.FallbackTestFramework.Throw(String message)
//      at FluentAssertions.Execution.TestFrameworkProvider.Throw(String message)
//      at FluentAssertions.Execution.CollectingAssertionStrategy.ThrowIfAny(IDictionary`2 context)
//      at FluentAssertions.Execution.AssertionScope.Dispose()
//      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)


public class Entity
{
    public int EntityId { get; set; }
    public string Name { get; set; }
}

public class EntityDto 
{
    public int Id { get; set; }
    public string Name { get; set; }

    public static EntityDto MapFromEntity(Entity entity)
    {
        return new EntityDto()
        {
            Name = entity.Name
        };
    }
}

Expected behavior:

I would expect the same behavior using WithMapping over a collection as I would with a single object

Actual behavior:

FluentAssertions does not map the property. If you use ExcludingMissingMembers then the collection assertion incorrectly passes.

Versions

Fluent Assertions 6.5.1
dotnet version 6.0.102

Additional Information

possible related issue #1838

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions