Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Moq - Ordered Setups (Expectations)

I am fairly new to Moq and cant work out how I am to order setups. I have the following code:

_orderRepository.Setup(r => r.Update(It.Is<Order>(a => ((int)a.OrderStatusReference.EntityKey.EntityKeyValues[0].Value) == 2)))
                        .Throws(exception)
                        .AtMost(5);

I want this to be executed 5 times (its retry logic, if the update fails). After the 5th time I want to setup and expect that it is successful (An exception is not thrown):

_orderRepository.Setup(r => r.Update(It.Is<Order>(a => ((int)a.OrderStatusReference.EntityKey.EntityKeyValues[0].Value) == 2))).AtMostOnce();

Unfortinatly it continues to use the 1st code sample, and never successfully updates.

If I were not using the Throws method, then I can use the Callback method, however its not available after a throw :(.

If there a way or is this a limitation of Moq?

like image 265
David Kiff Avatar asked Dec 01 '22 11:12

David Kiff


2 Answers

Bah... there are ways!

You can use a Queue to return a list of return values (strategy explained pretty well here: http://haacked.com/archive/2009/09/29/moq-sequences.aspx).

Here's a sample from that blog:

If you want this to work (which it doesn't):

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

Just do this instead:

Queue listOfOperations = new Queue<bool>(new bool[] { true, true, false });

reader.Setup(r => r.Read())
  .Returns(() => listOfOperations.Dequeue());

Each time Read() is called a new value from your Queue will be used.

Enjoy!

like image 100
Anderson Imes Avatar answered Dec 09 '22 18:12

Anderson Imes


I also needed the same thing and ended up with writing this extension method, which works for me:

public static class MoqExtensions {
    public static void Returns<TMock,TResult>(this ISetup<TMock, TResult> source, params TResult[] results) where TMock : class {
        int currentResultIndex = 0;

        source.Returns (() => {
            if(currentResultIndex >= results.Length) {
                currentResultIndex = 0;
            }

            return results [currentResultIndex++];
        });
    }
}

And sample usage is:

someMock.Setup(o => o.AMethodWithReturnTypeInt()).Returns(1, 2, 3, 4);

For this sample, if you call the stubbed method -let's say- 6 times, it will return 1, 2, 3, 4, 1, 2 respectively.

Hope this helps...

like image 27
Cihan Deniz Avatar answered Dec 09 '22 19:12

Cihan Deniz