Mocking Comparison - Part 5: Repetitions
In Part 4 we looked at how parameter constraints are handled and in Part 3 we looked at how to do interaction based tests with mocks. In this part we bring those two pieces together and add a little extra to check if a call was made a specific number of times.
Let’s just jump straight into the code shall we?
Rhino Mocks
Our test here is simply going to call a method a number of times and verify that the call was made the correct number of times using constraints to verify the correct calls. It’s a completely useless test, other than as a vehicle to show you how to do this sort of thing
[Fact]
public void Rhino_repetitions()
{
var monkey = MockRepository.GenerateMock<IMonkey>();
monkey.TryAddFleas(5);
monkey.TryAddFleas(-1);
monkey.TryAddFleas(9);
monkey.AssertWasCalled(m => m.TryAddFleas(0),
options => options.Constraints(
Is.GreaterThan(3) && Is.LessThanOrEqual(10)
)
.Repeat.Twice());
monkey.AssertWasCalled(m => m.TryAddFleas(-1),
options => options.Repeat.Once());
}
Note the important part, the .Repeat.Twice() and .Repeat.Once() calls. It’s these calls that define our expectations as to how many times the call should have been made.
Rhino also features a .Repeat.Time(n) call you can use as well if once or twice don’t cut it for you.
Moq
[Fact]
public void Moq_repetitions()
{
var monkey = new Mock<IMonkey>();
monkey.Object.TryAddFleas(5);
monkey.Object.TryAddFleas(-1);
monkey.Object.TryAddFleas(9);
monkey.Verify(m => m.TryAddFleas(
It.IsInRange(3,10,Range.Exclusive)
),
Times.Exactly(2));
monkey.Verify(m => m.TryAddFleas(-1), Times.Once());
}
Instead of using the word Repeat, Moq uses Times. Apart from that there is little difference.
NSubstitute
Unfortunately NSubstitute doesn’t support this feature yet as it’s still a maturing framework. If you really need to do this type of testing then you’ve got a few options – use Rhino or Moq, contribute to the NSubstitute project, or to just not do this type of testing :-).
Interaction based testing is valid at times, but it’s generally brittle and is usually a sign of “implementation verifying” tests rather than behaviour/specification verifying tests (but that’s an argument for another time)
Verdict: Moq wins out in this case simply because it’s constraint system is more terse than the Rhino one, but this is purely a personal taste thing.
Other posts in this series: