如何使用 StructureMap 依赖注入在 Web API 测试中模拟 AutoMapper IMapper 对象?
How to Mock an AutoMapper IMapper object in Web API Tests With StructureMap Dependency Injection?
所以我从头开始构建了一个 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));
}
我也在构建一些测试用例,实施最小起订量,这是我有点不确定的地方。每当调用我的控制器时,我都需要像这样传入一个 IMapper:
var mockMapper = new Mock<IMapper>();
var controller = new MyController(mockMapper.Object);
但是,我该如何配置 IMapper 以拥有正确的映射?重新创建我之前已经创建的相同逻辑来配置 Mapper 感觉是多余的。所以我想知道推荐的方法是什么?
这很简单:如果您模拟 IMapper
并将其想象成一个将数据从一个对象映射到另一个对象的完全抽象的概念,那么您必须将其视为一种抽象,而不是暗示背后有一个真正的自动映射器它。
首先你根本不应该注册任何现有的配置文件,你应该在给定另一个对象时将 IMapper.Map 方法设置为 return 特定对象。
因此,对于用于特定方法的每个配置文件,您必须进行设置,大致如下所示:
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
实现接收的数据。
这可能是我的另一个解决方案
//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 创建模拟对象,那么它将 return 您要求它 return。
所以我从头开始构建了一个 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));
}
我也在构建一些测试用例,实施最小起订量,这是我有点不确定的地方。每当调用我的控制器时,我都需要像这样传入一个 IMapper:
var mockMapper = new Mock<IMapper>();
var controller = new MyController(mockMapper.Object);
但是,我该如何配置 IMapper 以拥有正确的映射?重新创建我之前已经创建的相同逻辑来配置 Mapper 感觉是多余的。所以我想知道推荐的方法是什么?
这很简单:如果您模拟 IMapper
并将其想象成一个将数据从一个对象映射到另一个对象的完全抽象的概念,那么您必须将其视为一种抽象,而不是暗示背后有一个真正的自动映射器它。
首先你根本不应该注册任何现有的配置文件,你应该在给定另一个对象时将 IMapper.Map 方法设置为 return 特定对象。
因此,对于用于特定方法的每个配置文件,您必须进行设置,大致如下所示:
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
实现接收的数据。
这可能是我的另一个解决方案
//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 创建模拟对象,那么它将 return 您要求它 return。