Im using Rhino-Mocks 3.6 as mocking framework in my unit tests and have a problem with Repeat.Times()
:
I want to verify that a method on my mocked object is called exactly three times. According to the docs i should use Repeat.Times(3)
or Repeat.Times(3, 3)
.
But what i observe is that its verifying for at least three calls, so when i call the method four times, my test still passes. It fails when calling the method only two times.
Here is my code. Is there anything wrong with it?
MockRepository mocks = new MockRepository();
IJobServiceEvent mo开发者_运维问答ckedJSE;
using (mocks.Record())
{
mockedJSE = mocks.DynamicMock<IJobServiceEvent>();
Expect.Call(() => mockedJSE.TransactionListChanged(null))
.Repeat.Times(3);
}
using (mocks.Playback())
{
mockedJSE.TransactionListChanged(null);
mockedJSE.TransactionListChanged(null);
mockedJSE.TransactionListChanged(null);
mockedJSE.TransactionListChanged(null);
}
You need to use a StrictMock. A DynamicMock will allow methods calls that aren't expected. So your call to your method is expected three times (which happens). But when it happens a fourth time, it's not an error since you defined it as a DynamicMock (unexpected calls are allowed).
However, in the long run, using StrickMock can be a maintenance headache since your test knows too much about how the object is written (since you have to mock/stub every possible call that may be made).
I would recommend the AAA (Arrange, Act, Assert) syntax for your unit tests. Your test above could be written using a Stub, but still enforce the 3-limit call on your method:
IJobServiceEvent mockedJSE = MockRepository.GenerateStub<IJobServiceEvent>();
mockedJSE.TransactionListChanged(null);
mockedJSE.TransactionListChanged(null);
mockedJSE.TransactionListChanged(null);
mockedJSE.TransactionListChanged(null);
mockedJSE.AssertWasCalled(s => s.TransactionListChanged(null), o => o.Repeat.Times(3, 3));
UPDATE
To make sure only calls with certain args were made (although I do think this is basically a strict mock which can become a maintenance headache), use the arg constraints option three times to make sure those calls are made. Then have a final "AssertWasCalled" that ignores the arguments and make sure it only was called three times:
mockedJSE.AssertWasCalled(s => s.TransactionListChanged(null), o => o.IgnoreArguments().Repeat.Times(3, 3));
精彩评论