views:

268

answers:

2

Hi All,

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?

A: 

Moq doesn't support ordering of expectations. See here for more details.

Although I currently use Moq, I used to use RhinoMocks before, and it certainly has some features that I occasionally miss with Moq - ordered expectations being one of them.

Mark Seemann
I did read that article before posting here, however I was hoping a year later they saw sense and provided us with that feature! Hmm going to have to try and roll my own "ordering mechanism" if I have time.. Next project will use RhinoMocks if I have my way! :)... thanks.
David Kiff
+4  A: 

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!

Anderson Imes
Thats fine, you can do the same using callbacks. The question refers to doing that with regards to Throw. I need it to throw x times then return.
David Kiff
You are right... I missed that. Sorry for the confusion. I'll leave this here because it's a good pattern for returns, but the throws situation is still not really supported here, unless you can throw from a Returns.
Anderson Imes
Just a heads up but that last piece of code is incorrect. That will always return true. The queue creation needs to go outside the setup
James Hay
You are right... I wrote a similar closure bug just recently. I've learned my lesson :)
Anderson Imes
.Returns(listOfOperations.Dequeue()) should be .Returns(() => listOfOperations.Dequeue()) or .Returns(listOfOperations.Dequeue) (with missing parenthesis). Otherwise you bind the return value of .Read() to the value returned by listOfOperations.Dequeue() at the time of binding which will result in it returning true every time, independently of how many times you call it
Simen Echholt
@Simen Echholt: You are right. That's what I get for programming right in the comments box rather than testing.
Anderson Imes