如何使用映射选项模拟映射配置文件



我有一个使用IDictionary<string, object>传递值的映射配置文件。我被这样使用:

var viewModel = _mapper.Map<TransactionDetailsViewModel>(
transaction,
opt =>
{
opt.Items.Add( typeof(IClockService).Name, _systemClock );
}
);

我试着在单元测试中模拟它,但总是在这里得到NotSupportedException

Mock<IMapper> _mockMapper = new Mock<IMapper>();
_mockMapper
.Setup(
mm => mm.Map<TransactionDetailsViewModel>(
domainModel,
opt => opt.Items.Add( typeof(IClockService).Name, _systemClock )
)
)
.Returns( viewModel );

模拟这种映射方法的正确方法是什么?

这是StackTrace:

at Moq.MatcherFactory.CreateMatcher(Expression expression)
at Moq.MatcherFactory.CreateMatcher(Expression argument, ParameterInfo parameter)
at Moq.MatcherFactory.CreateMatchers(IReadOnlyList`1 arguments, ParameterInfo[] parameters)
at Moq.InvocationShape..ctor(LambdaExpression expression, MethodInfo method, IReadOnlyList`1 arguments, Boolean exactGenericTypeArguments)
at Moq.ExpressionExtensions.<Split>g__Split|4_1(Expression e, Expression& r, InvocationShape& p)
at Moq.ExpressionExtensions.Split(LambdaExpression expression)
at Moq.Mock.Setup(Mock mock, LambdaExpression expression, Condition condition)
at Moq.Mock`1.Setup[TResult](Expression`1 expression)
at Hosts.Api.Tests.TransactionsControllerTests.GetTransaction_WhenAdvance_ConvertsSpread() in C:UsersRSsourcereposProjectsrcUnitTestsHosts.Api.TestsOperationsTransactionsTransactionsControllerTests.cs:line 211

消息:

Unsupported expression: opt => 
opt.Items.Add(Services.ClockService.Interfaces.IClockService.Name,
value(Hosts.Api.Tests.TransactionsControllerTests)._systemClock)

通常我不会嘲笑映射器;我认为大多数时间集成测试映射配置文件是一件好事,但我会根据需要不时进行测试。

首先为选项指定匹配器:

mapperMock.Setup(x => x.Map<TransactionDetailsViewModel>(
transaction,
It.Is<Action<IMappingOperationOptions>>(opt => AddsItem(opt, nameof(IClockService), systemClock)))).Returns(viewModel);

您不能在委托本身上进行匹配,但在这种情况下,您可以在它正在做的事情上进行匹配——将项目添加到项目字典中。我已经将实际的比较委托给方法AddsItem,以保持代码的可读性。

public bool AddsItem(Action<IMappingOperationOptions> providedOptions, string key, object value)
{
var mappingOptions = new CustomMappingOperationOptions();
providedOptions.Invoke(mappingOptions);
return mappingOptions.Items.Any(x => x.Key.Equals(key) && x.Value.Equals(value));
}

基本上,比较解析委托正在做什么,并根据它是否完成了我们预期的操作返回true或false。裁剪并更改比较以适应,我在这里做假设。CustomMappingOperationOptions只是IMappingOperationOptions的一个快速本地实现,因为具体实现看起来有点麻烦,我们不需要它来进行测试。

最后,把所有的东西放在一起:

var mapperMock = new Mock<IMapper>();
mapperMock.Setup(x => x.Map<TransactionDetailsViewModel>(
transaction,
It.Is<Action<IMappingOperationOptions>>(opt => AddsItem(opt, nameof(IClockService), new ClockService())))).Returns(viewModel);
var mockedMapper = mapperMock.Object;
var result = mockedMapper.Map<TransactionDetailsViewModel>(transaction, opt => opt.Items.Add(nameof(IClockService), new ClockService()));

最新更新