Checkpoints

The test may need to use your mock object as part of its setup as well as a dependency of the specific code path under test.

For example:

#![allow(unused)]
fn main() {
pub struct Repository(/* ... */);

impl Repository {
    pub fn new<T: UserProvider>(up: T) -> Self {
        // ...
    }

    pub fn query<T: UserProvider>(&self, id: u32, up: T) -> Option<Entity> {
        // ...
    }
}
}

If you're mocking UserProvider and you want to test Repository::query, you'll need to use the mock for calling Repository::new first.

Expectations can leak

To get Repository::new to behave as expected, you'll need to set up some expectations on MockUserProvider.
You'll also need to set up expectations on MockUserProvider for Repository::query to behave as expected.

There's a risk that the expectations you set up for Repository::new will leak into Repository::query: they'll be executed when they shouldn't be, leading to confusing errors in your tests.
This can happen, in particular, when the code in Repository::new changes and stops performing one of the calls you set up expectations for.

Checkpoints

To prevent this from happening, you can use two different instances of MockUserProvider for those calls.
Alternatively, you can rely on checkpoints.
A checkpoint is a way of saying "Panic unless all expectations up to this point to have been met".

In this example, you can use a checkpoint to ensure that the expectations for Repository::new are met before you start setting up expectations for Repository::query.

#![allow(unused)]
fn main() {
#[test]
fn test_repository_query() {
    let mut mock = MockUserProvider::new();
    let mut repo = setup_repository(&mut mock);

    // Set up expectations for Repository::query
    // [...]

    // Call Repository::query
    // [...]
}

fn setup_repository(mock: &mut MockUserProvider) -> Repository {
    // Arrange
    mock.expect_is_authenticated()
        .returning(|_| true);
    // [...]

    // Act
    let repository = Repository::new(mock);

    // Verify that all expectations up to the checkpoint have been met
    mock.checkpoint();

    repository
}
}

If expectations are not met at the checkpoint, it will panic.
If they are met, the test will continue and all expectations will be reset.

Exercise

The exercise for this section is located in 03_mocks/04_checkpoints