28

我想断言一个方法只被调用一次。我正在使用 RhinoMocks 3.5。

这是我认为可行的方法:

[Test]
public void just_once()
{
    var key = "id_of_something";

    var source = MockRepository.GenerateStub<ISomeDataSource>();
    source.Expect(x => x.GetSomethingThatTakesALotOfResources(key))
        .Return(new Something())
        .Repeat.Once();

    var client = new Client(soure);

    // the first call I expect the client to use the source
    client.GetMeMyThing(key);

    // the second call the result should be cached
    // and source is not used
    client.GetMeMyThing(key);
}

GetMeMyThing()如果第二次调用调用,我希望此测试失败source.GetSomethingThatTakesALotOfResources()

4

7 回答 7

34

以下是我如何验证一个方法是否被调用一次。

[Test]
public void just_once()
{
    // Arrange (Important to GenerateMock not GenerateStub)
    var a = MockRepository.GenerateMock<ISomeDataSource>();
    a.Expect(x => x.GetSomethingThatTakesALotOfResources()).Return(new Something()).Repeat.Once();

    // Act
    // First invocation should call GetSomethingThatTakesALotOfResources
    a.GetMeMyThing();

    // Second invocation should return cached result
    a.GetMeMyThing();

    // Assert
    a.VerifyAllExpectations();
}
于 2009-02-20T05:54:22.463 回答
16

我一直在使用 AssertWasCalled 扩展来解决这个问题。这是我能找到/想出的最好的,但如果我不必指定两次调用会更好。

    [Test]
    public void just_once()
    {
        var key = "id_of_something";

        var source = MockRepository.GenerateStub<ISomeDataSource>();

        // set a positive expectation
        source.Expect(x => x.GetSomethingThatTakesALotOfResources(key))
            .Return(new Something())
            .Repeat.Once();

        var client = new Client(soure);
        client.GetMeMyThing(key);
        client.GetMeMyThing(key);

        source.AssertWasCalled(x => x.GetSomethingThatTakesALotOfResources(key),
                               x => x.Repeat.Once());
        source.VerifyAllExpectations();
    }
于 2009-05-20T05:21:01.223 回答
5

您可能对 Rhino Mocks 3.5 文档中的这一点感兴趣(引用如下)。看起来你需要模拟这个类,而不是存根它,它才能按照你期望的方式工作。

存根和模拟之间的区别

...

模拟是我们可以设置期望的对象,它将验证预期的动作确实发生了。存根是您用来传递给被测代码的对象。您可以对其设置期望,因此它会以某些方式起作用,但这些期望永远不会得到验证。存根的属性会自动表现得像普通属性一样,您不能对它们设置期望。

如果您想验证被测代码的行为,您将使用具有适当期望的模拟,并进行验证。如果您只想传递一个可能需要以某种方式执行的值,但不是此测试的重点,您将使用存根。

重要提示:存根永远不会导致测试失败。

于 2008-11-13T03:27:34.623 回答
2

这是我刚刚做的(由Ray Houston推荐)。我仍然会欣赏一个更优雅的解决方案......

[Test]
public void just_once()
{
    var key = "id_of_something";

    var source = MockRepository.GenerateStub<ISomeDataSource>();

    // set a positive expectation
    source.Expect(x => x.GetSomethingThatTakesALotOfResources(key))
        .Return(new Something())
        .Repeat.Once();

    var client = new Client(soure);

    client.GetMeMyThing(key);

    // set a negative expectation
    source.Expect(x => x.GetSomethingThatTakesALotOfResources(key))
        .Return(new Something())
        .Repeat.Never();

    client.GetMeMyThing(key);
}
于 2008-11-13T02:51:57.457 回答
2

您可以将委托传递给 WhenCalled 以计算调用次数:

...
uint callCount = 0;
source.Expect(x => x.GetSomethingThatTakesALotOfResources(key))
    .Return(new Something())
    .WhenCalled((y) => { callCount++; });
...
Assert.AreEqual(1, callCount);

此外,您应该使用模拟而不是存根,并验证模拟的期望。

于 2011-03-04T00:59:41.983 回答
0

如果你想确保一个方法只被调用一次,你可以创建严格的模拟。

var mock = MockRepository.GenerateStrictMock<IMustOnlyBeCalledOnce>();
mock.Expect(a => a.Process()).Repeat.Once();
var helloWorld= new HelloWorld(mock);

helloworld.Process()

mock.VerifyAllExpectations();
于 2017-11-01T15:11:08.770 回答
-1

拥有一个名为“Exactly”的功能可以方便地对可能进入无限循环的代码编写测试。我很想编写一个测试,以便对方法的第二次调用会引发异常。

一些 Python 库允许您对期望进行排序,因此第一个返回 false,第二个引发异常。

犀牛不会那样做。带有 .Once 的部分模拟将拦截第一次调用,其余的将传递给原始方法。所以这很糟糕,但这是真的。

您必须创建一个手模。派生一个“可测试”类,并赋予它在第一次跟注后加注的能力。

于 2009-04-21T15:04:06.387 回答