Jul 26, 2010

Mocking Comparison – Part 6: Multiple Calls

Our comparison of Rhino Mocks, Moq and NSubstitute continues with a look at how multiple calls to a mock are handled and what you do if you want to alter the return values on subsequent calls.

Consider the scenario where you have a method you’re calling that you want to be successful the first time you call it, but where subsequent calls should fail (such as trying to save the same data twice, etc).  How do you do this?

Rhino Mocks

In Rhino Mocks to set return values for multiple calls to a method you simply specify the return value that many times.  To avoid duplication of code you can use the repetition syntax we saw in Part 5.

[Fact]
public void Rhino_multiple_calls()
{
var monkey = MockRepository.GenerateMock<IMonkey>();

monkey.Stub(m => m.TryAddFleas(1)).Return(true).Repeat.Twice();
monkey.Stub(m => m.TryAddFleas(1)).Return(false);

Assert.True(monkey.TryAddFleas(1));
Assert.True(monkey.TryAddFleas(1));
Assert.False(monkey.TryAddFleas(1));
}

Given that we have set up the return value 3 times, what happens when we make the call a fourth time?  At this point Rhino Mocks, having exhausted it’s known set of return values, will start returning the default value.

What if you just want to return the value True for every call?  We would use the Repeat.Any() method as shown here:

[Fact]
public void Rhino_multiple_calls()
{
var monkey = MockRepository.GenerateMock<IMonkey>();

monkey.Stub(m => m.TryAddFleas(1)).Return(true).Repeat.Any();

Assert.True(monkey.TryAddFleas(1));
Assert.True(monkey.TryAddFleas(1));
}

Moq

Moq doesn’t have a nice way of defining mixed return values (not that I can find anyway) however you can implement the same thing using callbacks, which we’ll cover in a later post.

By default setting a return value on a method call will always return that value no matter how many times it is called, so we can at least do the following:

[Fact]
public void Moq_multiple_calls()
{
var monkey = new Mock<IMonkey>();
monkey.Setup(m => m.TryAddFleas(1)).Returns(true);

Assert.True(monkey.Object.TryAddFleas(1));
Assert.True(monkey.Object.TryAddFleas(1));
}

NSubstitute

The code for mixed return values in NSubstitute is so nice.  To handle multiple calls providing different return values you can just provide multiple values or use an array in the return statement as follows:

[Fact]
public void Nsubstitute_multiple_calls()
{
var monkey = Substitute.For<IMonkey>();

monkey.TryAddFleas(1).Returns(true,true,false);

Assert.True(monkey.TryAddFleas(1));
Assert.True(monkey.TryAddFleas(1));
Assert.False(monkey.TryAddFleas(1));
}

And if you just want to always return true, then it works just like Moq does (with the benefit of not requiring the .Object. tax in the assert statements:

[Fact]
public void Nsubstitute_multiple_calls()
{
var monkey = Substitute.For<IMonkey>();

monkey.TryAddFleas(1).Returns(true);

Assert.True(monkey.TryAddFleas(1));
Assert.True(monkey.TryAddFleas(1));
}

If you can’t tell, my decision on the best framework to choose goes to NSubstitute.  It has such a simple and elegant way to handle both requirements, and again, not a single lambda in site.  Excellent!

 

Other posts in this series:

3 comments:

  1. [Fact]
    public void Moq_multiple_calls()
    {
    var q = new Queue(new[] { true, true, false });
    var monkey = new Mock();
    monkey.Setup(m => m.TryAddFleas(1)).Returns(()=> q.Dequeue());

    Assert.True(monkey.Object.TryAddFleas(1));
    Assert.True(monkey.Object.TryAddFleas(1));
    Assert.False(monkey.Object.TryAddFleas(1));
    }

    ReplyDelete
  2. or with moq syntax:

    [Fact]
    public void Moq_multiple_calls()
    {
    var monkey = new Mock();
    monkey.SetupSequence(m => m.TryAddFleas(1)).Returns(true).Returns(true).Returns(false);

    Assert.True(monkey.Object.TryAddFleas(1));
    Assert.True(monkey.Object.TryAddFleas(1));
    Assert.False(monkey.Object.TryAddFleas(1));
    }

    ReplyDelete