ChatGPT解决这个技术问题 Extra ChatGPT

如何验证在 Moq 中没有调用该方法?

如何验证该方法未在 Moq 中调用?

它有类似 AssertWasNotCalled 的东西吗?

更新:从 3.0 版开始,可以使用新语法:

mock.Verify(foo => foo.Execute("ping"), Times.Never());
从 v4.8 开始,还有一个 alternative approach 也值得考虑。

M
MarredCheese

使用 Times.Never() 选项在测试后运行验证。

_mock.Object.DoSomething()
_mock.Verify(service => service.ShouldntBeCalled(), Times.Never());

这里的关键是,Verify(action, Never) 调用是在调用模拟之后进行的。我以为它正在为稍后调用 VerifyAll() 设置验证(这不起作用)
简单有效。谢谢。
不确定是否是因为较新的版本,但是如果您使用“MockBehavior.Strict”设置模拟并且不添加设置,那么如果调用该方法,它将失败。无需验证。
D
Dan Fish

更新:从第 3 版开始,请检查上述问题的更新或以下 Dann 的回答。

要么,让你的模拟严格,这样如果你调用一个你没有期望的方法,它就会失败

new Mock<IMoq>(MockBehavior.Strict)

或者,如果您希望您的模拟是松散的,请使用 .Throws( Exception )

var m = new Mock<IMoq>(MockBehavior.Loose);
m.Expect(a => a.moo()).Throws(new Exception("Shouldn't be called."));

...或 Callback() 设置一些可以断言的标志。
同样使用选项#2,您不能在一般的 Teardown 方法中使用 VerifyAll - 它会失败,说期望没有得到满足;当测试理想地通过时。
这并不是真正的“验证未调用”,因为它可能会在方法中被捕获并且仍然有效 - 提供误报!
现在不推荐使用 Expect
这可能是 2009 年最好的方式,但现在肯定不是。对不起
S
Shimmy Weitzhandler

窃取自:John Foster's answer to the question, "Need help to understand Moq better"

您可能想要测试的一件事是,当将 65 岁以上的人传递给方法 [Test] public void Some_over_65_does_not_pay_a_pension_contribution() { var mockPensionService = new Mock(); 时,不会调用 pay 方法。 var person = new Person("test", 66); var calc = new PensionCalculator(mockPensionService.Object); calc.PayPensionContribution(人); mockPensionService.Verify(ps => ps.Pay(It.IsAny()), Times.Never); }


L
Liam

这在最新版本的 Moq 中不起作用(至少从 3.1 开始),它应该在答案中提到的验证方法中指定。

实际上,最好在 Returns 语句之后指定 .AtMost(0)

var m = new Mock<ISomething>();
m.Expect(x => x.Forbidden()).Returns("foo").AtMost(0);

尽管“投掷”也有效,但恕我直言,AtMost(0) 更具表现力。


N
Neil

我意识到这是一个非常古老的问题,但它刚刚出现在我的侧边栏中,我想添加我的解决方案。

作为设置的一部分,许多单元测试似乎模拟了几个功能,但在测试期间并未使用。

当然最好启用严格模拟(这意味着任何未明确设置的内容都会引发异常),然后不要设置任何您不希望调用的函数。或者换一种说法,只设置一个测试期望调用的函数,其他任何东西都会抛出异常。

var thingBeingTested = new Mock<IThink>(MockBehaviour.Strict);

thingBeingTested.ThisWillThrowAnExceptionBecauseItHasNotBeenMocked();

M
MarredCheese

使用 VerifyNoOtherCalls(需要 Moq 4.8 或更高版本)

这个答案是一种间接的方法。不是检查一个特定的方法没有被调用,而是检查一般情况下没有发生意外的调用。

考虑到对模拟的彻底测试做了两件事:

验证是否进行了所有预期的呼叫 验证没有进行意外的呼叫

如果您已经在执行第 1 步,则添加第 2 步很简单:

// Step 1 (if relevant - see note below)
mock.Verify(..., Times.Exactly(2));
mock.Verify(..., Times.Once());
// ...

// Step 2
mock.VerifyNoOtherCalls();

笔记

如果您省略第 1 步,第 2 步将简单地确保根本没有对模拟进行调用。

这不需要严格的模拟。

来源:起订量快速入门


Z
Zia Qammar

假设你有这个方法并且你想测试它没有被调用

//Setup    
var databaseSessionMock = new Mock<IDatabaseSession>();
databaseSessionMock.Setup(m => m.Commit()).Returns(true).Verifiable();
RepositoryFactory.Configure<IDatabaseSession>(databaseSessionMock.Object);

你可以像这样测试

databaseSessionMock.Verify(m => m.Commit(It.IsAny()), Times.Never(), "Database Session mock object was not used");

A
Aaron Digulla

使用 .AtMostOnce();

真实测试后,再次调用该方法。如果它抛出异常,它就会被调用。


断言异常是由模拟框架引发的,是不是有点太晦涩难懂了?
为什么?只需检查异常的类型。如果它是我的起订量,你是安全的。
将验证与 Times.Never 一起使用是一个更好的选择……我同意 alex 的观点,即该解决方案有效,但绝对是晦涩难懂的。