Moq Sequences Revisited

tdd, code 0 comments suggest edit

A while back I wrote about mocking successive calls to the same method which returns a sequence of objects. Read that post for more context.

In that post, I had written up an implementation, but quickly was won over by a better extension method implementation from Fredrik Kalseth.

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

As good as this extension method is, I was able to improve on it today during a coding session. I was writing some code where I needed the second call to the same method to throw an exception and realized this extension wouldn’t allow for that.

However, it wasn’t hard to write an overload that allows for that.

public static void ReturnsInOrder<T, TResult>(this ISetup<T, TResult> setup,
    params object[] results) where T : class {
  var queue = new Queue(results);
    setup.Returns(() => {
        var result = queue.Dequeue();
        if (result is Exception) {
            throw result as Exception;
        }
        return (TResult)result;
    });
}

So rather than taking a parameter array of TResult, this overload accepts an array of object instances.

Within the method, we create a non generic Queue and then create a lambda that captures that queue in a closure. The lambda is passed to the Returns method so that it’s called every time the mocked method is called, returning the next item in the queue.

Here’s an example of the method in action:

var mock = new Mock<ISomeInterface>();
mock.Setup(r => r.GetNext())
    .ReturnsInOrder(1, 2, new InvalidOperationException());

Console.WriteLine(mock.Object.GetNext());
Console.WriteLine(mock.Object.GetNext());
Console.WriteLine(mock.Object.GetNext()); // Throws InvalidOperationException

In this sample code, I mock an interface so that when its GetNext method is called a third time, it will throw an InvalidOperationException.

I’ve found this to be a helpful and useful extension to Moq and hope you find some use for it if you’re using Moq.

NOTE: As Richard Reeves pointed out to me in an email, do be careful if you mock a property using this approach. If you evaluate the property while within a debugger, you will dequeue the element potentially causing maddening debugging difficulty.

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

Comments

avatar

10 responses

  1. Avatar for Josh Carroll
    Josh Carroll November 24th, 2010

    It's interesting that this is such a common situation for people. I blogged about this a few months ago, and didn't even realize you had previously written about it until someone left a comment.
    Honestly, I like the Queue approach better than what I came up with.
    You would think this would have been rolled into the framework by now. Also, watch out for multi-threaded code as you undoubtedly run into "The Collection Was Modified" exception.
    Overall though I have been extremely happy with Moq. That is the kind of API design people should strive for.

  2. Avatar for Jack Jackson
    Jack Jackson November 24th, 2010

    Hi Phil / Josh. I like the queue approach too. Is there any reason you're not commenting about MVC3 RC post?

  3. Avatar for mberube
    mberube November 24th, 2010

    Thanks Phil. Really interesting topic. Keep on the good work !

  4. Avatar for Alxandr
    Alxandr November 25th, 2010

    Intresting post. Just thought I'dd point out that I do think you have a typo: "mock.Setup(r => r.GetNext()" should probably be "mock.Setup(r => r.GetNext())"

  5. Avatar for haacked
    haacked November 25th, 2010

    @Alxandr Thanks for the correction! I fixed the typo.

  6. Avatar for Guest
    Guest December 24th, 2013

    Haack to the rescue again. I just came across this, but my requirements are slightly different. I wanted to return a "null" as the last instance.

    Took your code and added support for null - here you go!

    public static void ReturnsInOrder<t, tresult="">(this ISetup<t, tresult=""> setup,

    params object[] results) where T: class {

    var queue = new Queue(results);

    setup.Returns(() => {

    var result = queue.Dequeue();

    if (result is Exception) {

    throw result as Exception;

    }

    if (result == null) {

    return default(TResult);

    }

    return (TResult)result;

    });

    }

    And its use:

    mockQueue

    .Setup(x => x.GetNextMessage())

    .ReturnsInOrder(new InputMessage(), new InputMessage(), new InputMessage(), null);

  7. Avatar for Chris Sebok
    Chris Sebok December 24th, 2013

    Just tried to post this in your comments, but couldn't figure out how to format code properly, and it just looked a mess - so I created a blog post instead.

    I wanted to return null from a recursive mocked method, so I added support for returning null for reference types, and defaults for value types.

    http://blog.shadowmoses.co....

    Hopefully someone else will find that useful!

  8. Avatar for Mark Powell
    Mark Powell February 26th, 2015

    A little late to the party, but I believe Moq now supports this out of the box with SetupSequence!

    Usage:

    mock.SetupSequence(r => r.GetNext()).Returns(1).Return(2).Returns(new InvalidOperationException());

  9. Avatar for Weston McNamee
    Weston McNamee July 2nd, 2015

    This is great. I was looking for this exact thing, and in fact, at first I didn't think about writing a Moq extension method.

  10. Avatar for Weston McNamee
    Weston McNamee July 2nd, 2015

    I think you missed the point of this extension. If you are given an array of values to return, you can't use the default "chaining" you described.

    This helps most when writing Theories in XUnit. I can provide an array of return values in the TheoryData, then use this extension, because I don't know what the values are until runtime.