Search code examples
c#listinterfaceautomapper

AutoMapper failing assertion on List of interfaces


I want to map from SummaryDto to Summary.

public class SummaryDto
{
    public List<IOrderDto> Orders { get; init; }
}

public interface IOrderDto
{
    Guid Id { get; init; }
}

public class OnlineOrderDto : IOrderDto
{
    public Guid Id { get; init; }
    public string WebsiteReference { get; init; }
}

public class ShopOrderDto : IOrderDto
{
    public Guid Id { get; init; }
    public string ShopReference { get; init; }
}
public class Summary
{
    public List<IOrder> Orders { get; set; }
}

public interface IOrder
{
    Guid Id { get; set; }
}

public class OnlineOrder : IOrder
{
    public Guid Id { get; set; }
    public string WebsiteReference { get; set; }
}

public class ShopOrder : IOrder
{
    public Guid Id { get; set; }
    public string ShopReference { get; set; }
}

My Profile is as follows

public class OrdersProfile : Profile
{
    public OrdersProfile()
    {
        CreateMap<SummaryDto, Summary>();

        CreateMap<ShopOrderDto, ShopOrder>();

        CreateMap<ShopOrderDto, IOrder>()
            .As<ShopOrder>();

        CreateMap<OnlineOrderDto, OnlineOrder>();

        CreateMap<OnlineOrderDto, IOrder>()
            .As<OnlineOrder>();
    }
}

The code below executes fine and summary is correctly populated

var config = new MapperConfiguration(configure => configure.AddProfile<OrdersProfile>());
var mapper = config.CreateMapper();

var dto = new SummaryDto
{
    Orders = new()
    {
        new ShopOrderDto { Id = Guid.NewGuid(), ShopReference = "Random shop" },
        new OnlineOrderDto { Id = Guid.NewGuid(), WebsiteReference = "Random website" }
    }
};

var summary = mapper.Map<Summary>(dto); // Works fine

My problem lies in my unit test

public class MappingTests
{
    [Fact]
    public void Configuration_IsValid()
    {
        // ARRANGE
        var config = new MapperConfiguration(configure => configure.AddProfile<OrdersProfile>());

        // ACT

        // ASSERT
        config.AssertConfigurationIsValid(); // throws the following Exception

        //AutoMapper.AutoMapperConfigurationException : The following member on ConsoleAppAutoMapper.Objects.Summary cannot be mapped: 
        //    Orders
        //Add a custom mapping expression, ignore, add a custom resolver, or modify the destination type ConsoleAppAutoMapper.Objects.Summary.
        //Context:
           // Mapping to member Orders from ConsoleAppAutoMapper.Dtos.SummaryDto to ConsoleAppAutoMapper.Objects.Summary
        //Exception of type 'AutoMapper.AutoMapperConfigurationException' was thrown.
    }
}

What should I add/change in my profile to have my test pass?

I believe the difference is that when it is mapping at runtime it deals with either ShopOrderDto or OnlineOrderDto, but the assertion only deals with IOrderDto. I tried adding CreateMap<IOrderDto, IOrder>(); but this broke the runtime mapping.


Solution

  • Thanks to Lucian Bargaoanu for suggesting

    Try Include instead.

    CreateMap<IOrderDto, IOrder>()
        .Include<OnlineOrderDto, OnlineOrder>()
        .Include<ShopOrderDto, ShopOrder>();