Course contentsShow
← C#
Lesson 1635 of 1,90815. Software Quality and TestingFree lesson

Testing Sequence of Calls

Assert that dependencies are invoked in the exact order required by business logic.

In this lesson, you will learn how to enforce the specific chronological order in which your code interacts with its dependencies to ensure business logic integrity.

Sometimes, simply verifying that a method was called isn't enough; you must ensure it was called at the right time. For example, consider an OrderProcessor that must validate a payment before updating the inventory. If the code calls UpdateInventory() before ProcessPayment(), you have a critical bug. While the state might eventually be correct, the business process is fundamentally broken.

The "Sequence" Approach

When using mocking libraries like Moq or NSubstitute, you can define an order constraint. This effectively tells the test runner: "I don't just care that these methods were invoked; I care that MethodA finished before MethodB started."

If you are using Moq, you achieve this with a MockSequence object:

[Fact]
public void ProcessOrder_ShouldPerformActionsInCorrectOrder()
{
    var sequence = new MockSequence();
    var paymentMock = new Mock<IPaymentService>();
    var inventoryMock = new Mock<IInventoryService>();

    paymentMock.InSequence(sequence).Setup(x => x.Process(It.IsAny<Order>()));
    inventoryMock.InSequence(sequence).Setup(x => x.UpdateStock(It.IsAny<Order>()));

    var processor = new OrderProcessor(paymentMock.Object, inventoryMock.Object);
    processor.Execute(new Order());
}

In this snippet, if the OrderProcessor attempts to update the inventory before the payment is processed, the test will immediately fail. The MockSequence creates a strict timeline for the mock objects involved.

When to Use This

Be careful not to over-test. Using sequence verification makes your tests brittle because it couples your test to the implementation details of your method. Only use this when the sequence is a business requirement—such as security handshakes, stateful workflows, or transactional operations where the order of operations prevents race conditions or data corruption. If the order doesn't impact the outcome, testing for it adds unnecessary maintenance overhead.

Key Takeaway: Use sequence verification only when the order of operations is a fundamental requirement of your business logic, as it tightly couples your tests to your implementation details.