moq Validating call order with MockSequence


Example

Moq provides support for validating call order using MockSequence, however it only works when using Strict mocks. So, Given the following method to test:

public void MethodToTest()
{
    _utility.Operation1("1111");
    _utility.Operation2("2222");
    _utility.Operation3("3333");
}

It can be tested as follows:

// Create the mock, not MockBehavior.Strict tells the mock how to behave
var utilityMock = new Mock<IUtility>(MockBehavior.Strict);

// Create the MockSequence to validate the call order
var sequence = new MockSequence();

// Create the expectations, notice that the Setup is called via InSequence
utilityMock.InSequence(sequence).Setup(x => x.Operation1(It.IsAny<string>()));
utilityMock.InSequence(sequence).Setup(x => x.Operation2(It.IsAny<string>()));
utilityMock.InSequence(sequence).Setup(x => x.Operation3(It.IsAny<string>()));

// Run the method to be tested
var sut = new SystemUnderTest(utilityMock.Object);
sut.MethodToTest();

// Verify any parameters that are cared about to the operation being orchestrated.
// Note that the Verify calls can be in any order
utilityMock.Verify(x => x.Operation2("2222"));
utilityMock.Verify(x => x.Operation1("1111"));
utilityMock.Verify(x => x.Operation3("3333"));

The above example uses It.IsAny<string> when setting up the expectations. These could have used relevant strings ("1111", "2222", "3333") if more exact matches were required.

The error reported when calls are made out of sequence can be a bit misleading.

invocation failed with mock behavior Strict. All invocations on the mock must have a corresponding setup.

This is because, each Setup expectation is treated as if it doesn't exist until the previous expectation in the sequence has been satisfied.