我有一个带LogTrace的ILogger接口(字符串值,参数对象[]参数)。现在我想验证是否调用了LogTrace并且要记录的字符串包含一些id。问题是它可以被不同地调用。例如。 1)LogTrace(“MyString”+ id) 2)LogTrace(“MyString {0}”,id) 等等。
有没有一种方法可以让Moq验证所有场景?我只能想到创建一个手工制作的模拟器,它将格式化可用于验证的字符串。
答案 0 :(得分:11)
mock.Verify( m => m.LogTrace( It.IsAny<string>(), It.IsAny<object[]>() ) );
params object[]
无论如何都会以object[]
的方式传递给方法,所以你必须以某种方式匹配数组(例如,如上所述,这会接受任何内容)。
如果您需要对列表进行更多控制,请使用It.Is
匹配器,它允许您创建自己的谓词:
mock.Verify( m => m.LogTrace( It.IsAny<string>(),
It.Is<object[]>(ps =>
ps != null &&
ps.Length == 1 &&
ps[0] is int &&
(int)ps[0] == 5
) ) );
此示例显示如何验证参数列表是否为空且包含5
作为int
类型的唯一参数。
答案 1 :(得分:1)
您可以尝试使用Callback
,但它会变得相当复杂(未经过测试):
var mock = new Mock<ILogger>();
string trace = null;
mock.Setup(l => l.LogTrace(It.IsAny<string>(), It.IsAny<object[]>()))
.Callback((s1, par) =>
{
trace = string.Format(s1, par);
});
//rest of the test
Assert.AreEqual(expected, trace);
如果ILogger
具有较小的接口,您可以考虑手动实现存根(这将保留它应该记录的所有行),并在测试结束时验证。如果您记录了多行,那么这将是一个更易读的设置。
答案 2 :(得分:1)
我认为没有一种简单的方法可以满足您的需求。问题是您需要确保将某个值组合传递给您的方法,这会产生许多不同的可验证方案:
但是,Moq不支持可验证方法的不同参数之间的这种条件表达式。一种可能的解决方案是在任一参数中检查id的缺席,而不是 presence 。尝试类似:
mock.Verify(m => m.LogTrace(
It.Is<string>(s => !s.Contains(id)),
It.Is<object[]>(o => !o.Contains(id))), Times.Never());
我们在这里做的是验证是否满足 fail 条件 - 也就是说,你的字符串不包含id,你的对象数组也没有。我们使用Times.Never()来确保永远不会发生这种情况。
但请记住,乍一看代码可能并不明显;确保在写完后正确解释你的意图。