Moq验证方法失败,即使方法将被称为
我有一些麻烦使用Moq。单元测试之后会抛出异常,即使将调用相应的方法。Moq验证方法失败,即使方法将被称为
[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);
}
}
会出现此错误:
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")
我试过几个不同的验证的调用,但它不会工作。发生的错误似乎很混乱,它说LoadPlan("TestPlanDoNotUse")
从来没有被调用过,但它列出@ Performed invocations。
问题解决了:
我想我找到了问题,它不是一个起订量的问题。在sysCfg.Executor.CreateFinish(cfm)
中创建并启动了一个新线程。此线程尚未完成,因此factoryMock.Verify(...)
失败。
我用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);
在未被调用的Verifiable上,重要的是您期望中的参数与生产代码正在使用的参数相匹配。
关于Thread.Sleep的使用,请尽量避免使用它,因为它只会减慢测试以满足您最慢的机器。我通常会在测试中引入WaitHandles,以确保测试的运行速度与代码一样快。
取一个使用WaitHandles事件的peek here on a small utility。
你通常不会与验证(表达式,时间)方法一起选择在你的设置使用可验证()。如果您删除.Verifiable()调用,它会起作用吗?
如果删除了.Verifiable()调用我得到以下错误:'预期调用模拟正好1次,但是0次:f => f.CreateFinish(It.IsAny
这看起来有点更好,如果这确实是整个错误信息。现在看起来像CreateFinish不会被调用。它是否说过为CreateFinish执行的调用? – TheFogger 2011-05-31 09:00:26
不,它没有说关于CreateFinish的invoaction的任何事情,但我调试了它,我想我找到了问题:看到我的答案。感谢您的帮助 – Robar 2011-05-31 09:34:26
我想这是我的答案,但我相信这是一个比许多前面提到的更简单的解决方案。
我实现了一个WaitFor的功能,其利用一个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); } }
和测试代码看起来是这样的:
[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.
}
我使用了AutoResetEvents: – Robar 2011-06-27 06:29:58