Successive Method Calls With MoQ

code, tdd 0 comments suggest edit

UPDATE: For a better approach, check out MoQ Sequences Revisited.

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!

Tags: TDD, unit testing, MoQ

Found a typo or error? Suggest an edit! If accepted, your contribution is listed automatically here.

Comments

avatar

37 responses

  1. Avatar for Adam
    Adam September 29th, 2009

    Great post again Phil!

  2. Avatar for Eric Duncan
    Eric Duncan September 29th, 2009

    Pretty slick. I just began using Moq today actually, and tweeted a #moviesincode about it. And then, you tweet this. lol Nice timing.

  3. Avatar for Fabio Maulo
    Fabio Maulo September 29th, 2009

    Cool!

  4. Avatar for Jonathan van de Veen
    Jonathan van de Veen September 29th, 2009

    Don't you just love it when a plan comes together? Great code and good explanation.

  5. Avatar for Mark Heath
    Mark Heath September 29th, 2009

    thanks for sharing, this is a very useful technique

  6. Avatar for Dmitriy Nagirnyak
    Dmitriy Nagirnyak September 29th, 2009

    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.

  7. Avatar for Dmitriy Nagirnyak
    Dmitriy Nagirnyak September 29th, 2009

    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 :)

  8. Avatar for Fredrik Kalseth
    Fredrik Kalseth September 29th, 2009

    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);

  9. Avatar for Matt Hamilton
    Matt Hamilton September 29th, 2009

    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!

  10. Avatar for Stefano
    Stefano September 29th, 2009

    Lots of clever ideas, both in the post itself and in the comments.

  11. Avatar for Peli de Halleux
    Peli de Halleux September 29th, 2009

    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.

  12. Avatar for Haacked
    Haacked September 29th, 2009

    @Fredrik love it! I'm going to update the post to include that.

  13. Avatar for Michael
    Michael September 29th, 2009

    Awesome work you guys!

  14. Avatar for Scott Koon
    Scott Koon September 29th, 2009

    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...

  15. Avatar for Tim Van Wassenhove
    Tim Van Wassenhove September 30th, 2009

    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-...

  16. Avatar for Andrei Rinea
    Andrei Rinea September 30th, 2009

    @Phil and Matt : Ingenious and elegant indeed!
    @Adam : [Off Topic] is that a Gibson guitar in your avatar? :)

  17. Avatar for Roy Osherove
    Roy Osherove September 30th, 2009

    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.

  18. Avatar for Matt Hamilton
    Matt Hamilton September 30th, 2009

    @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.

  19. Avatar for Adam Greene
    Adam Greene September 30th, 2009

    This should be added to Moq.

  20. Avatar for Jan Deelstra
    Jan Deelstra October 2nd, 2009

    I second that.

  21. Avatar for I luv to Moq things
    I luv to Moq things October 3rd, 2009

    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?
    :)

  22. Avatar for Marcos
    Marcos December 22nd, 2009

    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

  23. Avatar for Marcos
    Marcos December 22nd, 2009

    PS: Was funny to found the post based on the same extension method name :P ReturnsInOrder
    Best Regards

  24. Avatar for Dominic
    Dominic March 18th, 2010

    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()));

  25. Avatar for Nick Foster
    Nick Foster May 6th, 2010

    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.

  26. Avatar for Ivan
    Ivan July 30th, 2010

    Why not:
    var reader = Mock<IDataReader>();
    int count = 0;
    reader.Setup(r => r.Read()).Returns(() => (++count < 3));
    Pretty simple, and gives you a count of the number of times Read() was called (somebody may have been calling it even after false was returned).
    I do like the generic ReturnsInOrder() extension method, though.

  27. Avatar for john.doe@gmail.com
    john.doe@gmail.com August 11th, 2011

    Why is "where T : class" needed?

  28. Avatar for Ahmed Subhani
    Ahmed Subhani May 1st, 2012

    Will reader.SetupSequence(r => r.Read())
    .Returns(true)
    .Returns(true)
    .Returns(false);
    not work?

  29. Avatar for anonymous
    anonymous June 12th, 2012

    Awesome post!
    I somehow got a great feeling when I wrote Returns(myQ.Dequeue)!!
    And then watched the test pass
    U Rock Phil!!

  30. Avatar for Trystan
    Trystan October 26th, 2012

    Hey Ahmed, well done for spotting that Moq already supports it with SetupSequence. This works for me.
    Why reinvent the wheel??

  31. Avatar for haacked
    haacked October 26th, 2012

    @Trystan: Look at the date of my blog post, I'm pretty sure SetupSequence came after! According to the commit, it was added two years ago. I should update my post though as I hadn't realized they added it!

  32. Avatar for Jacob Morris
    Jacob Morris January 24th, 2013

    Love it. Great work.

  33. Avatar for Mani Doost
    Mani Doost February 20th, 2013

    Nice job. my problem is when I want to read a value multiple times. Now, I put multiple values to the queue and it so painful to debug the application like this. I wonder if is there anyway to set the output value in specific events? 

  34. Avatar for Matt
    Matt November 21st, 2013

    Awesome. Solved my problem. Thanks!

  35. Avatar for Chris
    Chris February 12th, 2014

    Good Stuff!!! Thank You

  36. Avatar for FriKrtti
    FriKrtti November 3rd, 2016

    Great one

  37. Avatar for Rahul P Nath
    Rahul P Nath April 4th, 2017

    Nice one!