Successive Method Calls With MoQ

One area where using MoQ is confusing is when mocking successive calls to the same method of an object.

For example, I was writing some tests for legacy code where I needed to fake out multiple calls to a data reader. You remember data readers, don’t you?

Here’s a snippet of the code I was testing. Ignore the map method and focus on the call to reader.Read.

while(reader.Read()) {
  yield return map(reader);
}

Notice that there are multiple calls to reader.Read. The first couple times, I wanted Read to return true. The last time, it should return false. And here’s the code I hoped to write to fake this using MoQ:

reader.Setup(r => r.Read()).Returns(true);
reader.Setup(r => r.Read()).Returns(true);
reader.Setup(r => r.Read()).Returns(false);

Unfortunately, MoQ doesn’t work that way. The last call wins and nullifies the previous two calls. Fortunately, there are many overloads of the Returns method, some of which accept functions used to return the value when the method is called.

That’s the approach I found on Matt Hamilton’s blog post (Mad Props indeed!) where he describes his clever solution to this issue involving a Queue:

var pq = new Queue<IDbDataParameter>(new[]
    { 
        mockParam1.Object, 
        mockParam2.Object 
    });
mockCommand.Expect(c => c.CreateParameter()).Returns(() => pq.Dequeue());

Each time the method is called, it will return the next value in the queue.

One cool thing I stumbled on is that the syntax can be made even cleaner and more succinct by passing in a method group. Here’s my MoQ code for the original IDataReader issue I mentioned above.

var reader = new Mock<IDataReader>();
reader.Setup(r => r.Read())
  .Returns(new Queue<bool>(new[] { true, true, false }).Dequeue);

I’m defining a Queue inline and then passing what is effectively a pointer to its Dequeue method. Notice the lack of parentheses at the end of Dequeue which is how you can tell that I’m passing the method itself and not the result of the method.

Using this apporach, MoQ will call Dequeue each time it calls r.Read() grabbing the next value from the queue. Thanks to Matt for posting his solution! This is a great technique for dealing with sequences using MoQ.

UPDATE: There’s a great discussion in the comments to this post. Fredrik Kalseth proposed an extension method to make this pattern even simpler to apply and much more understandable. Why didn’t I think of this?! Here’s the extension method he proposed (but renamed to the name that Matt proposed because I like it better).

public static class MoqExtensions
{
  public static void ReturnsInOrder<T, TResult>(this ISetup<T, TResult> setup, 
    params TResult[] results) where T : class  {
    setup.Returns(new Queue<TResult>(results).Dequeue);
  }
}

Now with this extension method, I can rewrite my above test to be even more readable.

var reader = new Mock<IDataReader>();
reader.Setup(r => r.Read()).ReturnsInOrder(true, true, false);

In the words of Borat, Very Nice!

What others have said

Requesting Gravatar... Adam Sep 29, 2009 8:47 PM
# re: Successive Method Calls With MoQ
Great post again Phil!
Requesting Gravatar... Eric Duncan Sep 29, 2009 8:51 PM
# re: Successive Method Calls With MoQ
Pretty slick. I just began using Moq today actually, and tweeted a #moviesincode about it. And then, you tweet this. lol Nice timing.
Requesting Gravatar... Fabio Maulo Sep 29, 2009 9:42 PM
# re: Successive Method Calls With MoQ
Cool!
Requesting Gravatar... Jonathan van de Veen Sep 30, 2009 12:33 AM
# re: Successive Method Calls With MoQ
Don't you just love it when a plan comes together? Great code and good explanation.
Requesting Gravatar... Mark Heath Sep 30, 2009 1:44 AM
# re: Successive Method Calls With MoQ
thanks for sharing, this is a very useful technique
Requesting Gravatar... Dmitriy Nagirnyak Sep 30, 2009 2:28 AM
# re: Successive Method Calls With MoQ
The solution is interesting, but I often prefer to be explicit about order and write it in order. So I would probably just do this:

reader.Setup(r => r.Read()).Returns(true);
// Act
reader.Setup(r => r.Read()).Returns(true);
// Act
reader.Setup(r => r.Read()).Returns(false);
// Act & Verify

This is IMO much easier syntax to read and eveybody who comes to the code can understand it after 2 seconds.
The code with Queue is not so obvious.

First, when I saw it I thought it would always return the element at the top (true). The callback in Return creates the instance of a Queue every time and thus top element is always true.
Is it not?

So it took me much more than 2 seconds to understand the Lambda syntax. I see it just often gets overused.
Requesting Gravatar... Dmitriy Nagirnyak Sep 30, 2009 2:32 AM
# re: Successive Method Calls With MoQ
Additionally the lambda syntax requires reader to understand how Moq works, introduces unnecessary structure (Queue). This does decrease the readability of the test a lot.
But apart from that - very good idea :)
Requesting Gravatar... Fredrik Kalseth Sep 30, 2009 2:37 AM
# re: Successive Method Calls With MoQ
This is a great idea, however like Dmitriy says, it is not very readable and the syntax can be easilly misunderstood. You could fix this however by encapsulating it into an extension method:

public static class MoqExtensions
{
public static void ReturnsInSuccession<T, TResult>(this ISetup<T, TResult> setup, params TResult[] results)
where T : class
{
setup.Returns(new Queue<TResult>(results).Dequeue);

}
}

which will allow you to write your setup like this:

var reader = new Mock<IDataReader>();
reader.Setup(r => r.Read())
.ReturnsInSuccession(true, true, false);
Requesting Gravatar... Matt Hamilton Sep 30, 2009 2:51 AM
# re: Successive Method Calls With MoQ
Fredrik,

That extension method is essentially what I use nowadays, although I've called it "ReturnsInOrder". It makes for very simple, readable code.

Thanks for the link, Phil!
Requesting Gravatar... Stefano Sep 30, 2009 5:39 AM
# re: Successive Method Calls With MoQ
Lots of clever ideas, both in the post itself and in the comments.
Requesting Gravatar... Peli de Halleux Sep 30, 2009 8:39 AM
# re: Successive Method Calls With MoQ
You can write this with the Stubs framework:

bool[] values = new bool[] { true, true, false };
int counter = 0;
var reader = new SIDataReader() {
Read = () => values[counter++]
}

The C# compiler creates a closure around the locals and you simply iterate of the array of bools.
Requesting Gravatar... Haacked Sep 30, 2009 8:51 AM
# re: Successive Method Calls With MoQ
@Fredrik love it! I'm going to update the post to include that.
Requesting Gravatar... Michael Sep 30, 2009 9:40 AM
# re: Successive Method Calls With MoQ
Awesome work you guys!
Requesting Gravatar... Scott Koon Sep 30, 2009 9:46 AM
# re: Successive Method Calls With MoQ
Actually, I think using a Mock is the wrong approach. Jeremy Miller told me about the DataTableReader a while back and I like that approach much better.

www.lazycoder.com/.../mocking-idatareader-using...
Requesting Gravatar... Tim Van Wassenhove Sep 30, 2009 11:18 AM
# re: Successive Method Calls With MoQ
Hehe, i wrote that same extension method a couple of months ago when i read Matt's post..

cwww.timvw.be/setup-expectation-with-successive-...
Requesting Gravatar... Andrei Rinea Sep 30, 2009 1:07 PM
# re: Successive Method Calls With MoQ
@Phil and Matt : Ingenious and elegant indeed!
@Adam : [Off Topic] is that a Gibson guitar in your avatar? :)
Requesting Gravatar... Roy Osherove Sep 30, 2009 3:24 PM
# re: Successive Method Calls With MoQ
wow.
that would have worked out of the box with typemock isolator:

var reader = Isolate.Fake.Instance<IDataReader>();
Isolate.WhenCalled(()=> reader.Read()).WillReturn(true);
Isolate.WhenCalled(()=> reader.Read()).WillReturn(true);
Isolate.WhenCalled(()=> reader.Read()).WillReturn(false);

Isolator supports sequencing by default, and once the sequance is over, the last action in the sequence remains permanent.
Requesting Gravatar... Matt Hamilton Sep 30, 2009 9:30 PM
# re: Successive Method Calls With MoQ
@LazyCoder I also think that mocking IDataReader isn't the easiest way anymore. Check out my ToDataReader() extension method idea:

www.madprops.org/.../faking-idatareader-with-to...

I use that nowadays to test IDataReader code.
Requesting Gravatar... Adam Greene Oct 01, 2009 9:06 AM
# re: Successive Method Calls With MoQ
This should be added to Moq.
Requesting Gravatar... Jan Deelstra Oct 03, 2009 8:18 AM
# re: Successive Method Calls With MoQ
I second that.
Requesting Gravatar... I luv to Moq things Oct 03, 2009 11:40 AM
# re: Successive Method Calls With MoQ
Awesome piece of work, Moq is just so elegant and people coming up with these ideas make it even better. This should definitely be added to Moq.

You listening kzu?

:)
Requesting Gravatar... Marcos Dec 23, 2009 10:49 AM
# re: Successive Method Calls With MoQ
Lol I just sent this code to the Moq discussion group:

using Moq.Language.Flow;
using Moq.Utils;


namespace Moq
{
public static class MoqExtensionMethods
{
public static IReturnsResult<TMock> ReturnsInOrder<TMock, TResult>(this ISetup<TMock, TResult> setup, params TResult[] values) where TMock : class
{
var multipleReturn = new CircularValueProvider<TResult>(values);
return setup.Returns(multipleReturn.Next);
}
}
}

namespace Moq.Utils
{
public sealed class CircularValueProvider<T>
{
private readonly T[] mValuesToReturn;
private int mIndex = 0;

public CircularValueProvider(params T[] valuesToReturn)
{
mValuesToReturn = valuesToReturn;
}

public T Next()
{
if (mValuesToReturn.Length == 0)
return default(T);

var res = mValuesToReturn[mIndex];
mIndex = (mIndex + 1) % mValuesToReturn.Length;
return res;
}
}
}

Not is important to return the IReturnsResult<TMock> ?

The only diff is that this uses a circular list to return values

Cheers
Requesting Gravatar... Marcos Dec 23, 2009 10:51 AM
# re: Successive Method Calls With MoQ
PS: Was funny to found the post based on the same extension method name :P ReturnsInOrder

Best Regards
Requesting Gravatar... Dominic Mar 18, 2010 7:20 PM
# re: Successive Method Calls With MoQ
You could also do this with something like:
reader.Setup(r => r.Read()).Returns(true).CallBack(()=> reader.Setup(r => r.Read()).Returns(true).CallBack(()=>
reader.Setup(r => r.Read()).Returns(false)));

Again not the easiest to read but does the job. Also allows you to do more complicated things like throw an exception on subsequent calls.
reader.Setup(r => r.Read()).Returns(true).CallBack(()=> reader.Setup(r => r.Read()).Returns(true).CallBack(()=>
reader.Setup(r => r.Read()).Throws(new Exception()));

Requesting Gravatar... Nick Foster May 07, 2010 2:06 AM
# re: Successive Method Calls With MoQ
Can anyone get this to work in VB? I've translated it to:
<Extension()>
Public Sub ReturnsInOrder(Of T As Class, TResult)(ByVal setup As ISetup(Of T, TResult), ByVal ParamArray results As TResult())
setup.Returns(New Queue(Of TResult)(results).Dequeue)
End Sub

but it always returns me the first item in the array.

I've used Dominic's method above but would like the readability that the extension method would provide.

What do you have to say?

(will show your gravatar)
Please add 3 and 7 and type the answer here: