我想声明一个方法只被调用一次。我正在使用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()
,我希望此测试失败。
答案 0 :(得分:32)
以下是我验证方法被调用一次的方法。
[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();
}
答案 1 :(得分:15)
我一直在使用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();
}
答案 2 :(得分:5)
您可能对Rhino Mocks 3.5文档(引用如下)中的this bit感兴趣。看起来你需要模拟类,而不是存根,因为它可以按照你期望的方式工作。
存根和模拟之间的区别
...
模拟是我们可以设置的对象 期望,并将验证 预期的行动确实存在 发生了。存根是您的对象 用于传递给代码 测试。你可以设定期望 它,所以它会以某种方式行动, 但这些期望永远不会 验证。存根的属性会 自动表现得像平常一样 属性,你不能设置 对他们的期望。
如果要验证其行为 在测试的代码中,您将使用一个 嘲笑有适当的期望, 并验证。如果你想要 传递可能需要在a中执行的值 某种方式,但不是焦点 这个测试,你将使用存根。
重要提示:存根永远不会导致 测试失败。
答案 3 :(得分: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);
}
答案 4 :(得分:2)
您可以将委托传递给WhenCalled以计算来电:
...
uint callCount = 0;
source.Expect(x => x.GetSomethingThatTakesALotOfResources(key))
.Return(new Something())
.WhenCalled((y) => { callCount++; });
...
Assert.AreEqual(1, callCount);
此外,您应该使用模拟而不是存根,并验证对模拟的期望。
答案 5 :(得分:0)
如果要确保只调用一次方法,则可以创建严格模拟。
var mock = MockRepository.GenerateStrictMock<IMustOnlyBeCalledOnce>();
mock.Expect(a => a.Process()).Repeat.Once();
var helloWorld= new HelloWorld(mock);
helloworld.Process()
mock.VerifyAllExpectations();
答案 6 :(得分:-1)
拥有一个名为“Exactly”的功能,可以方便地编写可能会进入无限循环的代码测试。我很乐意编写一个测试,以便第二次调用方法会引发异常。
python的某些库允许您对期望进行排序,因此第一个返回false,第二个引发异常。
犀牛不会这样做。使用.Once的部分模拟将拦截第一个调用,其余部分将传递给原始方法。这太糟糕了,但这是真的。
你必须创建一个手工模拟。派生一个“可测试的”课程,并让它在第一次通话后加注。