Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Moq verify method fails even though method will be called

I have some troubles using 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.

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. This thread wasn't finished and so factoryMock.Verify(...) failed.

I used 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);
like image 428
Robar Avatar asked May 31 '11 07:05

Robar


People also ask

What does Moq verify do?

Verifies that all verifiable expectations have been met.

How do you test if a method is called in Nunit?

Verify(m => m. GetToken(It.Is<string>(c => c == "ssss", It.Is<bool>(x => x == false)), Times. Once);

What can be mocked with Moq?

You can use Moq to create mock objects that simulate or mimic a real object. Moq can be used to mock both classes and interfaces.

What is times once in Moq?

Between - Specifies that a mocked method should be invoked between from and to times. Exactly - Specifies that a mocked method should be invoked exactly times times. Never - Specifies that a mocked method should not be invoked. Once - Specifies that a mocked method should be invoked exactly one time.


3 Answers

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.

Regarding the use of Thread.Sleep, avoid it wherever possible as it will only slow down the tests to meet your slowest machine. I typically introduce WaitHandles into my tests to ensure that the tests run as fast as the code.

Take a peek here on a small utility that uses WaitHandles with events.

like image 58
bryanbcook Avatar answered Oct 29 '22 15:10

bryanbcook


You do not usually use Verifiable() in your setups in conjuction with the Verify(expr, times) methods. Does it work if you remove the .Verifiable() calls?

like image 44
TheFogger Avatar answered Oct 29 '22 15:10

TheFogger


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:

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.
    }
like image 28
Gudlaugur Egilsson Avatar answered Oct 29 '22 16:10

Gudlaugur Egilsson