c# - 如何在单元测试中从 Automapper 模拟 IValueResolver 的依赖关系

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

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(); 

被使用,然后在 Controller 中注入(inject)IMapper

在单元测试中,我尝试对映射器进行 stub

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

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

AutoMapper.AutoMapperMappingException : Error mapping types.

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 的依赖关系

最佳答案

在当前示例中,映射器在测试时无法解析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, .....) { ... }

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

关于c# - 如何在单元测试中从 Automapper 模拟 IValueResolver 的依赖关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59175241/

相关文章:

c# - Selenium 驱动程序服务未启动

c# - 检查装配体的身份?可能是因为它的强大名称?

c# - 在 C# 中运行多个任务时查找每个任务所花费的时间

c# - 如何使 ValidatesOnDataErrors 可绑定(bind)?

c# - 在 .NET 中将数组转换为 HashSet<T>

c# - 如何使用 ImageSharp(Web) 用图像压缩/变异流(IFormFile)

c# - Flex/Flash/Java/C# 中的漂亮日期文本

c# - 调用 Form.Show() 时设置表单的位置

asp.net-core - 在 Asp.net Core Identity 2.1x 中扩展 UserRoleStore

c# - 在 ASP NET Core 中禁用注册模板