For docs & instructions on the latest stable release, switch to main branch please
Moq.Contrib.InOrder is a library for ensuring that mock methods are called in correct order while strictly separating the acting & verification phase.
Register all mock setups that should be taken into account when verifying the call order in a var queue = CallQueue.Create(x => { /* here */});. To mark a mock method as relevant for order verification, use .SetupInOrder(...) instead of the normal .Setup(...) provided by moq (for every of moq's Setup methods, there is an InOrder version, e.g. SetupGetInOrder, SetupAddInOrder, etc).
Verify the call order after executing your test method by queue.VerifyOrder().
// Arrange
var mock = new Mock<IDummy>();
var sut = new TestedDummyClass(mock.Object);
var queue = CallQueue.Create(x0 =>
{
mock.SetupInOrder(x => x.ExecuteAction("a"), x0);
mock.SetupInOrder(x => x.ExecuteAction("b"), x0);
});
// Act
sut.TestedDummyMethod();
// Assert
queue.VerifyOrder();
/*
The only call order that will satisfy queue.VerifyOrder():
- ExecuteAction("a")
- ExecuteAction("b")
*/To define a loop for multiple setups, use .RegisterLoop(...). To define a loop for a single setup, use the times property of ever .SetupInOrder(...) method.
// Arrange
var mock = new Mock<IDummy>();
var sut = new TestedDummyClass(mock.Object);
var queue = CallQueue.Create(x0 =>
{
mock.SetupInOrder(x => x.ExecuteAction("a"), x0);
mock.SetupInOrder(x => x.ExecuteAction("b"), Times.Exactly(3), x0);
q.RegisterLoop(x1 =>
{
// these two methods should be called in a loop which is expected to execute twice
mock.SetupInOrder(x => x.ExecuteAction("c"), x1);
mock.SetupInOrder(x => x.ExecuteAction("d"), x1);
}, Times.Exactly(2));
});
// Act
sut.TestedDummyMethod();
// Assert
queue.VerifyOrder();
/*
The only call order that will satisfy queue.VerifyOrder():
- ExecuteAction("a")
- ExecuteAction("b")
- ExecuteAction("b")
- ExecuteAction("b")
- ExecuteAction("c")
- ExecuteAction("d")
- ExecuteAction("c")
- ExecuteAction("d")
*/You can also stack loop inside of loops.
var queue = CallQueue.Create(q =>
{
q.RegisterLoop(loop =>
{
mock.SetupInOrder(x => x.ExecuteAction("c"), loop);
mock.SetupInOrder(x => x.ExecuteAction("d"), loop);
loop.RegisterLoop(loop2 =>
{
mock.SetupInOrder(x => x.ExecuteAction("e"), loop2);
mock.SetupInOrder(x => x.ExecuteAction("f"), loop2);
}, Times.AtLeast(2));
}, Times.AtMost(2));
});For everyone using loose mocks, it's possible to make sure that no other invocations were performed on the mock via the PreventAllOtherInvocationsOf method
var mock = new Mock<IDummy>(MockBehavior.Loose);
var queue = CallQueue
.Create(q =>
{
mock.SetupInOrder(x => x.ExecuteAction("a"), q);
})
.PreventAllOtherInvocationsOf(mock);
mock.Object.ExecuteAction("a");
mock.Object.ExecuteAction("b");
queue.VerifyOrder(); // will throw due to 'ExecuteAction("b")' callOptionally, you can pass an ILogger<CallQueue> into CallQueue.Create that will log the expected and received calls.
var mock = new Mock<IDummy>();
var queue = CallQueue.Create(x0 =>
{
mock.SetupInOrder(x => x.ExecuteAction("a"), x0);
mock.SetupInOrder(x => x.ExecuteAction("b"), Times.AtLeast(2), x0);
x0.RegisterLoop(x1 =>
{
mock.SetupInOrder(x => x.ExecuteAction("c"), x1);
mock.SetupInOrder(x => x.ExecuteAction("d"), x1);
}, Times.Exactly(2));
},
_logger);
mock.Object.ExecuteAction("a");
mock.Object.ExecuteAction("b");
mock.Object.ExecuteAction("b");
mock.Object.ExecuteAction("c");
mock.Object.ExecuteAction("d");
mock.Object.ExecuteAction("c");
mock.Object.ExecuteAction("d");Producing the following output:
Information [0]: Expected Calls:
Information [0]: x => x.ExecuteAction("a")
Information [0]: (>2 times) x => x.ExecuteAction("b")
Information [0]: Loop: (2 times)
Information [0]: x => x.ExecuteAction("c")
Information [0]: x => x.ExecuteAction("d")
Information [0]: ----------------------------
Information [0]: Received Calls:
Information [0]: x => x.ExecuteAction("a")
Information [0]: x => x.ExecuteAction("b")
Information [0]: x => x.ExecuteAction("b")
Information [0]: x => x.ExecuteAction("c")
Information [0]: x => x.ExecuteAction("d")
Information [0]: x => x.ExecuteAction("c")
Information [0]: x => x.ExecuteAction("d")