【问题标题】:How to mock dependencies for IValueResolver from Automapper in unit tests如何在单元测试中从 Automapper 模拟 IValueResolver 的依赖项
【发布时间】:2020-03-29 05:02:17
【问题描述】:

previous question 之后我有一个简单的IValueResolver 实现

public class FileLinkResolver : IValueResolver<Configuration, ConfigurationDto, string>
{
    private readonly IFileStorage _fileStorage;

    public FileLinkResolver(IFileStorage fileStorage)
    {
        _fileStorage = fileStorage;
    }

    public string Resolve(Configuration source, ConfigurationDto destination, string destMember, ResolutionContext context)
    {
        return _fileStorage.GetShortTemporaryLink(source.Path);
    }
}

和简单的映射配置文件

public class MappingProfile : Profile
{
    public MappingProfile()
    {
        CreateMap<Configuration, ConfigurationDto>()
            .ForMember(dest => dest.FilePath, opt => opt.MapFrom<FileLinkResolver>());
    }
}

对于生产,它在以下设置时按预期工作

services.AddTransient<IFileStorage>(...);
services.AddAutoMapper(); 

被使用,然后在控制器中注入IMapper

在单元测试中我尝试存根映射器

var mapperStub = new Mapper(new MapperConfiguration(map => map.AddProfile(new MappingProfile())));

当我为方法 wwitch 运行测试应该返回映射的 dto 时,我得到了

AutoMapper.AutoMapperMappingException : 错误映射类型。

Mapping types:
Configuration -> ConfigurationDto
DataAccess.Models.Configuration -> Dto.ConfigurationDto

Type Map configuration:
Configuration -> ConfigurationDto
DataAccess.Models.Configuration -> Dto.ConfigurationDto

Destination Member:
FilePath

---- System.MissingMethodException : No parameterless constructor defined for this object.

我尝试将无参数构造函数添加到 FileLinkResolver 但随后,NullReferenceException

这是一个问题:如何解决 ValueResolver 的依赖关系

【问题讨论】:

    标签: c# .net asp.net-core dependency-injection automapper


    【解决方案1】:

    在当前示例中,映射器在测试时无法解析 IFileStorage 依赖关系。

    更改映射器的创建方式,使其更接近运行时的完成方式。

    IServiceCollection services = new ServiceCollection();
    //mocking service using MOQ
    var mock = Mock.Of<IFileStorage>(_ => 
        _.GetShortTemporaryLink(It.IsAny<string>()) == "fake link"
    );
    //adding mock to service collection.
    services.AddTransient<IFileStorage>(sp => mock);
    
    //adding auto mapper with desired profile;
    services.AddAutoMapper(typeof(MappingProfile));
    
    //...add other dependencies as needed to service collection.
    
    //...
    
    //build provider
    IServiceProvider serviceProvider = service.BuilderServiceProvider();
    
    //resolve mapper
    IMapper mapperStub = serviceProvider.GetService<IMapper>();
    
    //Or resolve subject under test where mapper is to be injected
    SubjectClass subject = serviceProvider.GetService<SubjectClass>();
    //assuming ctr: public SubjectClass(IMapper mapper, .....) { ... }
    

    现在从技术上讲,这并不是在模拟值解析器。它模拟解析器的依赖关系,并使用配置文件中的实际解析器。但这应该在测试目标时提供所需的行为。

    【讨论】:

      猜你喜欢
      • 2012-07-11
      • 2023-03-13
      • 2018-06-28
      • 2013-07-07
      • 2023-03-12
      • 1970-01-01
      • 2016-02-19
      • 2015-08-25
      • 1970-01-01
      相关资源
      最近更新 更多