【问题标题】:How to Mock an AutoMapper IMapper object in Web API Tests With StructureMap Dependency Injection?如何使用 StructureMap 依赖注入在 Web API 测试中模拟 AutoMapper IMapper 对象?
【发布时间】:2016-03-18 00:54:47
【问题描述】:

所以我从头开始构建了一个 WebAPI,包括我在网上找到的一些最佳实践,例如依赖注入和域使用自动映射器进行 DTO 映射等。

我的 API 控制器现在看起来与此类似

public MyController(IMapper mapper)
{
}

和 AutoMapper 注册表:

public AutoMapperRegistry()
{
    var profiles = from t in typeof(AutoMapperRegistry).Assembly.GetTypes()
                   where typeof(Profile).IsAssignableFrom(t)
                   select (Profile)Activator.CreateInstance(t);

    var config = new MapperConfiguration(cfg =>
    {
        foreach (var profile in profiles)
        {
            cfg.AddProfile(profile);
        }
    });

    For<MapperConfiguration>().Use(config);
    For<IMapper>().Use(ctx => ctx.GetInstance<MapperConfiguration>().CreateMapper(ctx.GetInstance));
}

我还在构建一些测试用例,实施 MOQ,这就是我感到有点不确定的地方。每当调用我的控制器时,我都需要像这样传入一个 IMapper:

var mockMapper = new Mock<IMapper>();
var controller = new MyController(mockMapper.Object);

但是,我如何配置 IMapper 以获得正确的映射?重新创建我之前已经创建的相同逻辑来配置 Mapper 感觉是多余的。所以我想知道推荐的方法是什么?

【问题讨论】:

  • 几乎可以肯定你不需要模拟它,并且可以在测试设置中传入普通的 AutoMapper:模拟的映射器实际上不会映射对象,它只会记录它被要求这样做并返回你告诉它的东西。
  • 测试是一个不同的项目。法线映射器在基础 api 项目中定义。这不会违背分离的目的吗?
  • 你想在控制器级别的测试中完成什么?我同意@stuartd 的观点,即您不应该在控制器测试中模拟 AutoMapper。如果您使用真正的 AutoMapper 实现和设置,您的测试也将帮助您发现 AutoMapper 映射问题。

标签: unit-testing asp.net-web-api moq automapper structuremap


【解决方案1】:

这很简单:如果您模拟 IMapper 并将其想象为将数据从一个对象映射到另一个对象的完全抽象概念,那么您必须将其视为一种抽象,而不是暗示它背后有一个真正的自动映射器。

首先,您根本不应该注册任何现有配置文件,而应该设置 IMapper.Map 方法以在给定另一个对象时返回特定对象。

因此,对于用于特定方法的每个配置文件,您必须进行设置,大致如下所示:

var mockMapper = new Mock<IMapper>();
mockMapper.Setup(x => x.Map<DestinationClass>(It.IsAny<SourceClass>()))
    .Returns((SourceClass source) =>
        {
            // abstract mapping function code here, return instance of DestinationClass
        });

在这种情况下,您的测试对实际的 IMapper 实现一无所知 - 它只是使用它的方法来获取您期望从实际的 IMapper 实现接收的数据。

【讨论】:

  • Here 是另一个参考
【解决方案2】:

这可能是另一种解决方案

        //auto mapper configuration
        var mockMapper = new MapperConfiguration(cfg =>
        {
            cfg.AddProfile(new AutoMapperProfile()); //your automapperprofile 
        });
        var mapper = mockMapper.CreateMapper();

然后像这样调用控制器

var controller = new YourController(imapper:mapper,..otherobjects..);

这样它将达到目的,否则如果您为 IMapper 创建模拟对象,那么它将返回您要求它返回的内容。

【讨论】:

  • 这个救了我。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-01-16
  • 1970-01-01
  • 2019-11-27
  • 1970-01-01
  • 2017-11-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多