Automapper 无法在单元测试项目中映射外键属性

Posted

技术标签:

【中文标题】Automapper 无法在单元测试项目中映射外键属性【英文标题】:Automapper unable to map foreign key properties in unit test project 【发布时间】:2022-01-06 08:22:05 【问题描述】:

我已经声明了一个将实体映射到 DTO 的映射。该 DTO 具有对另一个 DTO 的外键引用,该 DTO 必须由 automapper 使用 ProjectTo 进行映射。这在运行解决方案时工作得非常好,但是当我在单元测试中使用地图时,直到我从 DTO 中删除外键属性后才会工作。我认为我的 AutoMapper 设置中缺少某些内容,但我不确定。

模型如下所示:

public class PendingReportDto

    public Guid Id  get; set; 
    public Guid PatientId  get; set; 
    public long Identifier  get; set; 
    public DatabaseType Database  get; set; 
    public DateTime? ReportedDate  get; set; 
    public PatientDto Patient  get; set; 
    public IdentifierType IdentifierType  get; set; 

地图是这样的:

CreateMap<Report, PendingReportDto>()
            .ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id))
            .ForMember(dest => dest.Database, opt => opt.MapFrom(src => src.Database))
            .ForMember(dest => dest.PatientId, opt => opt.MapFrom(src => src.PatientId))
            .ForMember(dest => dest.ReportedDate, opt => opt.MapFrom(src => src.ReportedDate))
            .ForMember(dest => dest.Identifier, opt => opt.MapFrom(src => src.Identifier))
            .ForMember(dest => dest.IdentifierType, opt => opt.MapFrom(src => src.IdentifierType))
            .ForMember(dest => dest.Patient, opt => opt.MapFrom(src => src.Patient));

Patient 有自己的地图,可以自己完美运行。 上面的地图是这样使用的:

return ReadContext.Reports
            .Where(x => x.Database == databaseType && x.ReportedDate == null)
            .ProjectTo<PendingReportDto>(_mapper.ConfigurationProvider)
            .ToListAsync(cancellationToken: cancellationToken);

执行此操作时,我收到以下错误:

System.ArgumentNullException: Value cannot be null. (Parameter 'bindings')

Automapper 在单元测试项目中是这样设置的:

public static class SetupAutomapper

    public static IMapper Setup()
    
        var config = new MapperConfiguration(opts =>
        
            var profiles = typeof(MappingProfile).Assembly.GetTypes().Where(x => typeof(MappingProfile).IsAssignableFrom(x));
            foreach (var profile in profiles.Distinct())
            
                opts.AddProfile(Activator.CreateInstance(profile) as MappingProfile);
            
        );

        return config.CreateMapper();
    

如果我使用 select 语句而不是使用 ProjectTo 映射到我的 DTO,它会起作用。

更新:

进一步调查表明,罪魁祸首可能是我在运行单元测试时运行的是内存数据库,而不是我的常规数据库。如果我将其换掉,即使使用相同的数据集,它也会按预期工作。这可能是 EF Core 内存数据库和自动映射器的错误吗?

【问题讨论】:

进一步调查表明,罪魁祸首可能是我在运行单元测试时运行的是内存数据库,而不是我的常规数据库。如果我将其换掉,即使使用相同的数据集,它也会按预期工作。这可能是 EF Core 内存数据库和自动映射器的错误吗? 此外,配置文件似乎有效,正如我在上面的评论中所述。如果我将数据库从内存数据库更改为常规数据库,那么它工作得很好。此外,当我使用内存数据库时,除了通过反向导航属性进行映射之外,一切正常。 我看到您链接到程序集扫描以添加配置,但这肯定不是唯一的方法,因为 AutoMapper API 有一种方法可以一次添加一个配置文件。在另一个项目中,我只是添加了一个类型,它可以通过几种不同的方式完成 @LucianBargaoanu 我尝试通过添加配置文件。装配扫描,但它没有任何区别。我认为这可能是 Automapper 与 In-memory ef core 结合使用的东西 提供者所做的与 AM 无关。如果它适用于真实的数据库,您只需要使您的测试基础设施更接近真实的东西。我相信很多人已经这样做了。 【参考方案1】:

所以我很确定我发现了使用 ProjectTo 映射反向导航属性的问题。问题不在于 Automapper 本身或我在测试设置中配置它的方式。

罪魁祸首似乎是数据库提供者:Entity Framework Core in-memory db。

如果我用 localdb 或常规 MS SQL DB 替换数据库,它就可以正常工作。 in-memory db provider 有一定的限制,这似乎限制了 ProjectTo 与 Automapper 的使用。

来源:https://docs.microsoft.com/en-us/ef/core/testing/

如何设置本地数据库:

private static void SetupLocalDb(DbContextOptionsBuilder builder)

    builder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=Testing;Trusted_Connection=True;");

【讨论】:

以上是关于Automapper 无法在单元测试项目中映射外键属性的主要内容,如果未能解决你的问题,请参考以下文章

.net webapi+autofac+autoMapper 单元测试

Automapper 链/嵌套对象映射抛出异常

一文为你详细讲解对象映射库AutoMapper所支持场景

AutoMapper实际项目运用

对象映射工具AutoMapper介绍

如何在 AutoMapper 中映射通用结构类型