犀牛模拟: Repeat.Once() 不起作用?

15

有谁能告诉我为什么下面的测试在世界上不会失败吗?

[Test]
public void uhh_what() {
    var a = MockRepository.GenerateMock<IPrebuiltNotifier>();
    a.Expect(x => x.Notify()).Repeat.Once();
    a.Notify();
    a.Notify();
    a.VerifyAllExpectations();
}

我真的需要第二个人来确认我不是疯了……现在我担心所有的测试都不可靠。


1
为了以后的参考(尽管Rhino Mock已经过时),我要补充一下,像mock.Stub(x => x.Notify()).Repeat.Once();这样的'Stub'-'Once'-'VerifyAllExpectations'也不能按预期工作。相反,应该使用AssertWasCalled。具体可以参考这里:https://benbiddington.wordpress.com/2009/06/23/rhinomocks-repeat-times/。 - LosManos
2个回答

27

已经有一个RhinoMocks小组的讨论帖子

GenerateMock创建动态模拟。该动态模拟允许未指定(=预期)的调用。如果发生这种情况,它只会返回null(或返回类型的默认值)。

注意:Repeat是一种行为规范(如Stub),而不是期望值规范,即使在期望值中指定了也是如此

如果要避免超过一定数量的调用,则可以编写:

[Test]
public void uhh_what() 
{
    var a = MockRepository.GenerateMock<IPrebuiltNotifier>();
    a.Expect(x => x.Notify()).Repeat.Once();
    a.Stub(x => x.Notify()).Throw(new InvalidOperationException("gotcha"));
    a.Notify();

    // this fails
    a.Notify();

    a.VerifyAllExpectations();
}
或者
[Test]
public void uhh_what() 
{
    var a = MockRepository.GenerateMock<IPrebuiltNotifier>();
    a.Notify();
    a.Notify();

    // this fails
    a.AssertWasCalled(
      x => x.Notify(), 
      o => o.Repeat.Once());
}

1
哦!我不知道AssertWasCalled有第二个参数,你可以进行更多的规范,这改变了一切! - George Mauer
1
如果你曾经遇到PartialMock,那么这个问题也是一样的。 - Dennis
1
第一种解决方案(抛出异常)如果Notify被调用超过一次,将会导致测试失败。然而,如果它只被调用一次(至少我认为被测试的代码应该这样做),测试将不会像应该的那样通过,因为它期望Notify的第二个调用却从未到来。设置a.Expect(x => x.Notify()).Repeat.Once(),然后跟着a.Stub(x => x.Notify()).Throws(...)来完成任务。 - geoffmazeroff
@geoffmazeroff:你说得对。这个答案已经存在了两年以上,没有人注意到它...谢谢,我会修复它的。 - Stefan Steinegger

9
当使用GenerateMock(或者一般的动态模拟)时,我总是会在脑海中插入以下内容:
a.Expect(x => x.Notify()).Repeat.*[至少]*一次();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接