如何使用StrcutureMap依赖注入在Web API测试中模拟AutoMapper IMapper对象?

时间:2016-03-18 00:54:48

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

所以我从头开始构建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的相同逻辑感觉是多余的。所以我想知道这样做的推荐方法是什么?

2 个答案:

答案 0 :(得分:9)

这很简单:如果你模拟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实现中获得的数据。

答案 1 :(得分:5)

这可能是我的另一种解决方案

        //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创建模拟对象,则它将返回您要求它返回的内容。