简体   繁体   English

即使将调用方法,起订量验证方法也会失败

[英]Moq verify method fails even though method will be called

I have some troubles using Moq.我在使用 Moq 时遇到了一些麻烦。 Following unit test throws an exception, even though the according method will be called.以下单元测试会引发异常,即使将调用相应的方法。

[TestMethod]
public void CreateFinishTest() {
    // mock methods 
    factoryMock.Setup(f => f.LoadPlan("TestPlanDoNotUse")).Returns(testPlan).Verifiable();
    factoryMock.Setup(f => f.CreateFinish(It.IsAny<CreateFinishMessage>(), It.IsAny<string>())).Returns(testFinish.Id).Verifiable();

    try {
        var cfm = new CreateFinishMessage() {
            ClientId = 11,
            MessageId = 23456,
            CustomerId = 6,
            FinishName = "MyFinish",
            PlanId = "TestPlanDoNotUse"
        };
        var cmd = sysCfg.Executor.CreateFinish(cfm); // calls LoadPlan with cfm.PlanId and CreateFinish with cfm and cfm.PlanId
        sysCfg.Executor.Execute(cmd);

        factoryMock.Verify(f => f.LoadPlan("TestPlanDoNotUse"), Times.Exactly(1));
        factoryMock.Verify(f => f.CreateFinish(It.IsAny<CreateFinishMessage>(), It.IsAny<string>()), Times.Exactly(1));
    } catch (Exception exc) {
        Assert.Fail(exc.Message);
    }
}

This Error occurs:发生此错误:

Expected invocation on the mock exactly 1 times, but was 0 times: f => f.LoadPlan("TestPlanDoNotUse")

Configured setups:
f => f.LoadPlan("TestPlanDoNotUse"), Times.Once

Performed invocations:
IFactory.LoadPlan("TestPlanDoNotUse")
Factory.CreateFinish(IndiValue.LiveMarket.IndiCore.Communication.MessagingFormat.CreateFinishMessage, "MyFinish")

I've tried several different Verify-Calls but it won't work.我尝试了几种不同的验证呼叫,但它不起作用。 And the Error which occurs seems quite confusing it's says that LoadPlan("TestPlanDoNotUse") is never called, but it's listed @ Performed invocations.并且发生的错误似乎很令人困惑,它说LoadPlan("TestPlanDoNotUse")从未被调用,但它被列出 @Performed 调用。

Problem solved:问题解决了:

I think i found the problem, it wasn't a Moq problem.我想我找到了问题,这不是起订量问题。 In sysCfg.Executor.CreateFinish(cfm) a new thread was created and started.sysCfg.Executor.CreateFinish(cfm)中创建并启动了一个新线程。 This thread wasn't finished and so factoryMock.Verify(...) failed.该线程尚未完成,因此factoryMock.Verify(...)失败。

I used AutoResetEvents:我使用了 AutoResetEvents:

// create AutoResetEvent triggers
AutoResetEvent m_testTrigger1 = new AutoResetEvent(false);

// mock methods     
factoryMock.Setup(f => f.LoadPlan(It.IsAny<string>())).Returns(testPlan).Callback(() => m_testTrigger1.Set());

// do something

// wait for triggers
bool didReturn1 = m_testTrigger1.WaitOne(timeOut);

You do not usually use Verifiable() in your setups in conjuction with the Verify(expr, times) methods.您通常不会在设置中将 Verifiable() 与 Verify(expr, times) 方法结合使用。 Does it work if you remove the.Verifiable() calls?如果您删除 the.Verifiable() 调用,它会起作用吗?

On the Verifiable not being called, it's important that the arguments in your expectation match the arguments that are being used by the production code.在未调用 Verifiable 时,重要的是您期望中的 arguments 与生产代码使用的 arguments 匹配。

Regarding the use of Thread.Sleep , avoid it wherever possible as it will only slow down the tests to meet your slowest machine.关于Thread.Sleep的使用,尽可能避免使用它,因为它只会减慢测试速度以满足最慢的机器。 I typically introduce WaitHandles into my tests to ensure that the tests run as fast as the code.我通常将 WaitHandles 引入我的测试中,以确保测试与代码一样快地运行。

Take a peek here on a small utility that uses WaitHandles with events. 在这里查看一个使用 WaitHandles 处理事件的小实用程序

I guess this is a me-too answer, but I believe this to be a simpler solution than many of the mentioned before.我想这也是我的答案,但我相信这是一个比前面提到的许多更简单的解决方案。

I implemented a WaitFor function which utilizes a lambda callback to evaluate a condition:我实现了一个 WaitFor function ,它利用 lambda 回调来评估条件:

public static void WaitFor(Func<bool> action, long timeoutMillis = 10000) { Stopwatch elapsed = Stopwatch.StartNew(); elapsed.Start(); // ReSharper disable once LoopVariableIsNeverChangedInsideLoop while (.action()) { if (elapsed.ElapsedMilliseconds > timeoutMillis) { throw new TimeoutException("Timed out waiting for condition to become true after " + elapsed;ElapsedMilliseconds + " ms"). } Thread;Sleep(0); } }

and the test code looks like this:测试代码如下所示:

    [Test]
    public void ShouldNackUnparsableInboundMessage()
    {   
        var nackCalled = false;
        _mock.Setup(m => m.BasicNack(999, false, false)).Callback(() =>
        {
            nackCalled = true;
        });

        ... do whatever which invokes the call on another thread.

        WaitFor(() => nackCalled);
        // Test will fail with timeout if BasicNack is never called.
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM