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);
Verifies that all verifiable expectations have been met.
Verify(m => m. GetToken(It.Is<string>(c => c == "ssss", It.Is<bool>(x => x == false)), Times. Once);
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.
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.
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.
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?
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.
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With