Setup(...)
和Verify(...)
有两种模式:
选项1
// Define mock
_textTransformerMock = new Mock<ITextTransformer>();
// Setup with Any String
_textTransformerMock.Setup(t => t.Transform(It.IsAny<string>())).Returns("transformed");
并且在验证时使用以下代码:
_textTransformerMock.Verify(t => t.Transform(It.Is<string>(s => s == "input")), Times.Once);
选项2
// Define mock
_textTransformerMock = new Mock<ITextTransformer>();
// Setup with the input string we expect
_textTransformerMock.Setup(t => t.Transform("input")).Returns("transformed");
并且在验证时使用以下代码:
_textTransformerMock.Verify(t => t.Transform("input"), Times.Once);
选项2似乎对我有些锁定?
我希望有人可以分享他们的经验。
答案 0 :(得分:1)
这是非常基于意见的,但这是我的意见。
没有用:
t => t.Transform(It.Is<string>(s => s == "input")
由于用于字符串的==
的重载完全等于默认的EqualityComparer<string>
,即顺序区分大小写的比较,因此较短:
t => t.Transform("input")
给出完全相同的结果。
否则,最好使用It.Is
,例如It.Is<string>(s => s.StartsWith("in"))
或其他任何东西。当然,它可以同时用于Setup
和Verify
。
另一个带有It.Is
的示例是It.Is((string s) => string.Equals(s, "input", StringComparison.CurrentCultureIgnoreCase))
。
除此之外,这两个示例之间的区别在于您是Setup
输入参数的所有值,还是Setup
仅输入参数的期望值。我更喜欢后者(选项2)。如果您只希望一个参数是相关的,为什么还要为所有参数设置Moq?
您可以走得更远,并使用严格的模拟,即:
_textTransformerMock = new Mock<ITextTransformer>(MockBehavior.Strict);
这意味着Moq将不接受没有设置“匹配”的任何参数值。在这种情况下,如果您正在测试的代码向您的方法发送了意外的参数,您将获得异常。
话虽这么说,It.IsAny
在无法提前告知将出现哪个值或何时无法提供具有相同值的对象(例如,引用类型的对象)时非常有用等式语义(与string
不同),在这种情况下,您不能将与被测系统将使用的相同的 instance 传递给Moq。