如何对使用IMappingAction的AutoMapper Profile进行单元测试?
无需DI容器的AutoMapper IMappingAction单元测试方案
针对你遇到的两个测试问题,有两种无需依赖Microsoft DI容器的轻量化解决方案:
方案一:手动实例化IMappingAction并直接绑定到映射配置
这种方式跳过AutoMapper的服务构造逻辑,直接把带依赖的Action实例传给映射配置:
先Mock你的
ISerialNumberProvider服务:var mockSerialNumberProvider = new Mock<ISerialNumberProvider>(); // 预设Mock的返回值,比如: mockSerialNumberProvider.Setup(p => p.GenerateSerialNumber(It.IsAny<Student>())) .Returns("TEST-SERIAL-001");手动实例化
SetSerialNumberAction,注入Mock的服务:var setSerialNumberAction = new SetSerialNumberAction(mockSerialNumberProvider.Object);构建
MapperConfiguration时,直接将Action绑定到对应的映射:var config = new MapperConfiguration(cfg => { cfg.CreateMap<Student, StudentDto>() .AfterMap(setSerialNumberAction); // 直接传入已实例化的Action });创建Mapper并执行映射,最后验证逻辑:
var mapper = config.CreateMapper(); var student = new Student { /* 测试数据 */ }; var dto = mapper.Map<StudentDto>(student); // 验证SerialNumber是否正确 Assert.Equal("TEST-SERIAL-001", dto.SerialNumber); // 验证服务方法是否被调用 mockSerialNumberProvider.Verify(p => p.GenerateSerialNumber(student), Times.Once);
方案二:用ConstructServicesUsing自定义服务构造逻辑
如果想复用原有的Profile配置,不想重复编写映射规则,可以通过ConstructServicesUsing告诉AutoMapper如何创建依赖实例:
同样先Mock
ISerialNumberProvider:var mockSerialNumberProvider = new Mock<ISerialNumberProvider>(); mockSerialNumberProvider.Setup(p => p.GenerateSerialNumber(It.IsAny<Student>())) .Returns("TEST-SERIAL-002");构建配置时,通过
ConstructServicesUsing指定类型构造逻辑:var config = new MapperConfiguration(cfg => { cfg.ConstructServicesUsing(type => { // 当AutoMapper需要创建SetSerialNumberAction时,手动注入Mock服务 if (type == typeof(SetSerialNumberAction)) { return new SetSerialNumberAction(mockSerialNumberProvider.Object); } // 测试场景下一般不需要处理其他类型,若有需要可扩展 throw new InvalidOperationException($"无法构造类型: {type.FullName}"); }); // 加载你原本的Profile cfg.AddProfile<StudentMappingProfile>(); });后续的映射和验证步骤和方案一一致,直接创建Mapper并验证即可。
这两种方案都能解决"无参数构造函数"的报错,同时让你完全控制ISerialNumberProvider的Mock实例,方便验证映射逻辑。
内容的提问来源于stack exchange,提问作者Enrico Massone
相关产品推荐
相关产品推荐

