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

C# 如何使用映射选项模拟映射配置文件,c#,.net-core,automapper,moq,C#,.net Core,Automapper,Moq,我有一个映射配置文件,它使用IDictionary传递值。我被这样使用: var viewModel = _mapper.Map<TransactionDetailsViewModel>( transaction, opt => { opt.Items.Add( typeof(IClockService).Name, _systemClock ); } ); 模拟这种映射方法的正确方法是什么 这是StackTrace: at

我有一个映射配置文件,它使用
IDictionary
传递值。我被这样使用:

var viewModel = _mapper.Map<TransactionDetailsViewModel>(
    transaction,
    opt =>
    {
        opt.Items.Add( typeof(IClockService).Name, _systemClock );
    }
);
模拟这种映射方法的正确方法是什么

这是
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:\Users\RS\source\repos\Project\src\UnitTests\Hosts.Api.Tests\Operations\Transactions\TransactionsControllerTests.cs:line 211

通常我不会嘲笑地图绘制者;我认为大部分时间集成测试映射配置文件是一件好事,但是我会根据需要不时地做

首先为选项指定匹配器:

mapperMock.Setup(x => x.Map<TransactionDetailsViewModel>(
        transaction,
        It.Is<Action<IMappingOperationOptions>>(opt => AddsItem(opt, nameof(IClockService), systemClock)))).Returns(viewModel);
基本上,比较解决了委托在做什么,并根据它是否做了我们期望的事情返回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()));
var-mapperMock=new Mock();
mapperMock.Setup(x=>x.Map(
交易
Is(opt=>AddsItem(opt,nameof(IClockService),newclockservice()))。返回(viewModel);
var mockedMapper=mapperMock.Object;
var result=mockedMapper.Map(事务,opt=>opt.Items.Add(nameof(IClockService),new ClockService());

我建议您不要模拟
IMapper
:它在所有情况下的行为都应该相同:(单元测试、集成测试和正常运行)-而且AutoMapper无论如何都支持DI。你想在测试中模仿它有什么原因吗?(您总是可以为测试使用不同地配置AutoMapper,但这与模拟它不同)。@Dai我同意更好的选择是在测试服务中注入真实版本的mapper。在当前的单元测试中,以及在类中的其他单元测试中,映射器被模拟。在更改了测试服务的实现并向映射配置文件添加了小的更改之后,我不想更新所有的单元测试。在我试图模仿选项的方式中,我只是在徘徊到底什么是不正确的。没有选项的版本按预期工作。从哪里抛出
NotSupportedException
?(即代码< StackTrace >代码>什么?)<代码>域名模型>代码> CAMAPRE到<代码>事务< /代码>?BTW,考虑使用<代码> Name(ICCLoService)< /COD>而不是<代码> Type(ICCuleService)。Name < /C> >(<代码> Name of())/代码>对于泛型类型参数OFC无效。谢谢。我会的。这是堆栈跟踪:
在Moq.MatcherFactory.CreateMatcher(表达式表达式)
在Moq.MatcherFactory.CreateMatcher(表达式参数,参数信息)
在Moq.MatcherFactory.CreateMatchers(IReadOnlyList
1个参数,
参数信息[]参数)在Moq.ExpressionExtensions.g|u Split | 4|u 1(表达式e、表达式r、调用形状和p)…的Moq.InvocationShape..ctor(LambdaExpression expression expression、MethodInfo method、IReadOnlyList
1参数、Boolean exactGenericTypeArguments)上,谢谢rgvlee。我最终还是使用了RealMappingProfile,但这个解决方案正是我所寻找的,而且很有效。我试着模仿
IMappingOperationOptions
inside
Additems()
如下:
public bool Additems(Action opt,string key,object value){var-mapOptions=new Mock();mapOptions.Setup(x=>x.Items).返回(new-StringDictionary());opt.Invoke(mapOptions.object);return mappoptions.Object.Items.Any(x=>x.Key.Equals(Key)&&x.Value.Equals(Value));}
Hi Roman,干得好,在这种情况下,使用新字典返回效果很好。
mapperMock.Setup(x => x.Map<TransactionDetailsViewModel>(
        transaction,
        It.Is<Action<IMappingOperationOptions>>(opt => AddsItem(opt, nameof(IClockService), systemClock)))).Returns(viewModel);
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));
}
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()));