使用moq验证对具有param参数的函数的调用

时间:2014-02-12 13:29:06

标签: c# function moq

我有一个带LogTrace的ILogger接口(字符串值,参数对象[]参数)。现在我想验证是否调用了LogTrace并且要记录的字符串包含一些id。问题是它可以被不同地调用。例如。 1)LogTrace(“MyString”+ id) 2)LogTrace(“MyString {0}”,id) 等等。

有没有一种方法可以让Moq验证所有场景?我只能想到创建一个手工制作的模拟器,它将格式化可用于验证的字符串。

3 个答案:

答案 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)

我认为没有一种简单的方法可以满足您的需求。问题是您需要确保将某个值组合传递给您的方法,这会产生许多不同的可验证方案:

  • 字符串包含ID AND参数包含ID - 传递
  • 字符串包含 ID AND参数不包含ID - 传递
  • 字符串不包含 ID AND参数包含ID = pass
  • 字符串不包含ID AND 参数不包含ID - 失败

但是,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()来确保永远不会发生这种情况。

但请记住,乍一看代码可能并不明显;确保在写完后正确解释你的意图。