I want to assert that a method is called exactly one time. I'm using RhinoMocks 3.5.
Here's what I thought would work:
[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);
}
I want this test to fail if the second invocation of GetMeMyThing()
calls source.GetSomethingThatTakesALotOfResources()
.
Here's how I'd verify a method is called once.
[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();
}
I have been using the AssertWasCalled extension to get around this problem. This is the best I could find/come up with but it would be better if I didn't have to specify the call twice.
[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();
}
You may be interested in this bit from the Rhino Mocks 3.5 Documentation (quoted below). Looks like you need to mock the class, not stub it, for it to work the way you expect.
The difference between stubs and mocks
...
A mock is an object that we can set expectations on, and which will verify that the expected actions have indeed occurred. A stub is an object that you use in order to pass to the code under test. You can setup expectations on it, so it would act in certain ways, but those expectations will never be verified. A stub's properties will automatically behave like normal properties, and you can't set expectations on them.
If you want to verify the behavior of the code under test, you will use a mock with the appropriate expectation, and verify that. If you want just to pass a value that may need to act in a certain way, but isn't the focus of this test, you will use a stub.
IMPORTANT: A stub will never cause a test to fail.
Here is what I just did (as recommended by Ray Houston). I would still appreciate a more elegant solution...
[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);
}
You can pass a delegate to WhenCalled to count calls:
...
uint callCount = 0;
source.Expect(x => x.GetSomethingThatTakesALotOfResources(key))
.Return(new Something())
.WhenCalled((y) => { callCount++; });
...
Assert.AreEqual(1, callCount);
Also, you should use a mock not a stub, and verify expectations on the mock too.
You can create strict mock, if you want to ensure that a method is called only once.
var mock = MockRepository.GenerateStrictMock<IMustOnlyBeCalledOnce>();
mock.Expect(a => a.Process()).Repeat.Once();
var helloWorld= new HelloWorld(mock);
helloworld.Process()
mock.VerifyAllExpectations();
Having a feature called "Exactly" would be handy to write tests on code that might otherwise get into an infinite loop. I would love to write a test such that the second call to a method would raise an exception.
Some libraries for python allow you to sequence expectations, so the first returns false and the second raises an exception.
Rhino won't do that. A partial mock with .Once will intercept the first call, and the rest will be passed on to the original method. So that sucks, but it's true.
You'll have to create a hand-mock. Derive a "testable" class, and give it the ability to raise after the first call.
来源:https://stackoverflow.com/questions/286093/asserting-that-a-method-is-called-exactly-one-time