Moq:如何验证 Action<T> 参数是一个空函数?
Moq: How to verify that an Action<T> argument is an empty function?
在 Automapper v9 中,Map()
方法具有以下签名:
TDestination Map<TDestination>(object source, Action<IMappingOperationOptions> opts);
我们经常做如下用法:
_mapper.Map<SomeClass>(srcObj, _ => { });
问题:对于最小起订量,我如何测试第二个参数是否确实为空Action
?
我知道如何忽略第二个参数,但这并不是一个很好的测试...
_mapper.Setup(m => m.Map<SomeClass>(srcObj, It.IsAny<Action<IMappingOperationOptions>>()))
.Returns(mapped);
奖励积分:我将如何测试非空 Action
?
我相信您可以分析操作方法的编译 (IL) 代码以确定它是否为空:
private bool IsEmptyAction(Action<IMappingOperationOptions> a)
{
return a.Method.GetMethodBody().GetILAsByteArray().SequenceEqual(new byte[] { 0x0, 0x2a });
}
0x0, 0x2a
值是通过观察 IL 对于空操作的样子获得的。对于具有泛型类型参数的操作和具有 none.
的操作都是相同的
那么你可以像这样使用这个方法:
It.Is<Action<IMappingOperationOptions>>(a => IsEmptyAction(a))
并且显然测试相反的只是否定条件的情况(!IsEmptyAction(a)
)。
要测试某些值的选项,您可能需要模拟 IMappingOperationOptions
:
private bool IsItemsExist(Action<IMappingOperationOptions> a, Func<IDictionary<string, object>, bool> itemsChecker)
{
// Create mock of options
var optionsMock = new Mock<IMappingOperationOptions>();
var itemsDictionary = new Dictionary<string, object>();
optionsMock.SetupGet(o => o.Items).Returns(itemsDictionary);
// Call action
a(optionsMock.Object);
// Call check function
return itemsChecker(itemsDictionary);
}
然后你可以将它应用到你的主要模拟中:
test
.Setup(t => t.TestMethod(It.Is<Action<IMappingOperationOptions>>(a => !IsItemsExist(a, d => d.ContainsKey("test")))))
.Throws(new Exception("must contain test"));
然后你可以这样测试它:
test.Object.TestMethod(o => o.Items.Add("test", "moo"));
Assert.Throws<Exception>(() => test.Object.TestMethod(o => o.Items.Add("hello", "test")));
当然这只是一个示例,因此您可以根据需要使其更通用或更不通用等。
在 Automapper v9 中,Map()
方法具有以下签名:
TDestination Map<TDestination>(object source, Action<IMappingOperationOptions> opts);
我们经常做如下用法:
_mapper.Map<SomeClass>(srcObj, _ => { });
问题:对于最小起订量,我如何测试第二个参数是否确实为空Action
?
我知道如何忽略第二个参数,但这并不是一个很好的测试...
_mapper.Setup(m => m.Map<SomeClass>(srcObj, It.IsAny<Action<IMappingOperationOptions>>()))
.Returns(mapped);
奖励积分:我将如何测试非空 Action
?
我相信您可以分析操作方法的编译 (IL) 代码以确定它是否为空:
private bool IsEmptyAction(Action<IMappingOperationOptions> a)
{
return a.Method.GetMethodBody().GetILAsByteArray().SequenceEqual(new byte[] { 0x0, 0x2a });
}
0x0, 0x2a
值是通过观察 IL 对于空操作的样子获得的。对于具有泛型类型参数的操作和具有 none.
那么你可以像这样使用这个方法:
It.Is<Action<IMappingOperationOptions>>(a => IsEmptyAction(a))
并且显然测试相反的只是否定条件的情况(!IsEmptyAction(a)
)。
要测试某些值的选项,您可能需要模拟 IMappingOperationOptions
:
private bool IsItemsExist(Action<IMappingOperationOptions> a, Func<IDictionary<string, object>, bool> itemsChecker)
{
// Create mock of options
var optionsMock = new Mock<IMappingOperationOptions>();
var itemsDictionary = new Dictionary<string, object>();
optionsMock.SetupGet(o => o.Items).Returns(itemsDictionary);
// Call action
a(optionsMock.Object);
// Call check function
return itemsChecker(itemsDictionary);
}
然后你可以将它应用到你的主要模拟中:
test
.Setup(t => t.TestMethod(It.Is<Action<IMappingOperationOptions>>(a => !IsItemsExist(a, d => d.ContainsKey("test")))))
.Throws(new Exception("must contain test"));
然后你可以这样测试它:
test.Object.TestMethod(o => o.Items.Add("test", "moo"));
Assert.Throws<Exception>(() => test.Object.TestMethod(o => o.Items.Add("hello", "test")));
当然这只是一个示例,因此您可以根据需要使其更通用或更不通用等。