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: