Mocking
Unit Testing
Software Testing
Test Automation
Mock Methods

Asserting successive calls to a mock method

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

When a mock method is called more than once, a good test often needs more than called or call_count. You may need to prove that the calls happened in the right order, with the right arguments, and sometimes only at specific positions in the sequence.

What "Successive Calls" Usually Means

There are a few different assertions hidden inside this phrase:

  • the method was called a certain number of times
  • the first call used one argument and the second used another
  • the calls happened in a specific order
  • the call sequence may include other interactions in between

Most mocking libraries record call history, so the trick is choosing the right assertion for the level of strictness you need.

Python unittest.mock

In Python, Mock and MagicMock keep a full call history. That makes successive-call assertions straightforward.

Here is a simple example:

python
1from unittest.mock import Mock, call
2
3
4def send_notifications(notifier):
5    notifier.send("starting")
6    notifier.send("finished")
7
8
9notifier = Mock()
10send_notifications(notifier)
11
12notifier.send.assert_has_calls([
13    call("starting"),
14    call("finished"),
15])
16assert notifier.send.call_count == 2

assert_has_calls checks the sequence of calls in order by default. If the order matters, this is usually the cleanest assertion.

If you want to inspect individual calls directly, use call_args_list:

python
1from unittest.mock import Mock
2
3service = Mock()
4service.save("draft")
5service.save("published")
6
7first_args = service.save.call_args_list[0].args
8second_args = service.save.call_args_list[1].args
9
10assert first_args == ("draft",)
11assert second_args == ("published",)

This is helpful when only certain positions in the sequence matter or when the assertion needs custom logic.

Allowing Extra Calls Around the Sequence

Sometimes you only care that a particular subsequence happened, not that it was the entire history. assert_has_calls still helps there:

python
1from unittest.mock import Mock, call
2
3logger = Mock()
4logger.info("boot")
5logger.info("start job")
6logger.info("finish job")
7logger.info("cleanup")
8
9logger.info.assert_has_calls([
10    call("start job"),
11    call("finish job"),
12])

That confirms the subsequence exists in order. It does not require those to be the only calls.

If you want the order to be irrelevant, pass any_order=True, but only do that when sequence truly does not matter.

Mockito Has the Same Idea

In Java with Mockito, the equivalent tool is InOrder:

java
1import static org.mockito.Mockito.inOrder;
2import static org.mockito.Mockito.mock;
3
4import org.mockito.InOrder;
5
6interface Notifier {
7    void send(String message);
8}
9
10public class Demo {
11    public static void main(String[] args) {
12        Notifier notifier = mock(Notifier.class);
13
14        notifier.send("starting");
15        notifier.send("finished");
16
17        InOrder inOrder = inOrder(notifier);
18        inOrder.verify(notifier).send("starting");
19        inOrder.verify(notifier).send("finished");
20    }
21}

The underlying principle is the same across libraries: verify the interaction history rather than only checking the final state of the mock.

Make Assertions Specific but Not Fragile

Overly broad assertions miss bugs. Overly strict assertions make tests brittle. For example, asserting every debug log call in exact order may make the test fail for harmless refactors.

A good rule is to verify only the calls that represent business behavior. If the order of two writes is important for correctness, assert it. If the order of internal log messages is incidental, do not.

Common Pitfalls

The most common mistake is checking only call_count and assuming that proves the right arguments were used. It does not.

Another issue is asserting the full call history when only one or two critical interactions actually matter. That makes tests noisy and fragile.

Developers also forget that some libraries record nested or chained interactions differently. Always inspect the mock's recorded calls when an assertion behaves unexpectedly.

Summary

  • Use call-history assertions when you need to verify more than simple invocation count.
  • In Python, assert_has_calls and call_args_list are the main tools for successive-call checks.
  • In Mockito, InOrder is the standard way to verify call sequence.
  • Assert the order only when order is part of the behavior under test.
  • Keep interaction assertions focused so tests stay informative without becoming brittle.

Course illustration
Course illustration

All Rights Reserved.