Testing if a log call was made

I'm making a change to a library to add a log::warn!("...") call to be made under a certain circumstance. I want to add a test case for this (to ensure the warning occurs)

For example I have a function like

pub fn thing(x: i64) {
    if x > 100 {
        warn!("Possible mistake..");
    }
    // ...
}

How could I go about making a test case to verify a warning occurs while calling thing(101) but not thing(99)?

I guess I want some kind of mock logger backend - does such a library exist? It's a tricky thing to search for (searching for combination of test/mock/logging finds lots of different issues!)

1 Like

Why don't you try creating your own mock logger by implementing log::Log? Then create a static reference to it with Box::leak, and call log::set_logger with your logger (rather than calling env_logger::init or whatever you normally use in your main function). Your logger can use a Mutex<VecDeque<...>> and push each important message to the queue, then your test code can regularly drain the queue to check the logs.

See the testing_logger crate.

Instead of hard-coding calls to log, what about using dependency injection to pass in something that receives warnings? For example, in gcode the Parser accepts a set of Callbacks to warn the user when a problem happens.

It's a little more heavy-handed than swapping out the logger, but if emitting warnings are important enough to your API that you want to write tests for them you may as well go all the way.

Interesting responses - thanks all! The testing_logger crate is exactly what I was looking for.

So my silly example would be tested as such:

pub fn thing(x: i64) {
    if x > 100 {
        warn!("Possible mistake..");
    }
    // ...
}

#[test]
fn test_warning() {
    testing_logger::setup();

    thing(101);

    // Expecting one warning
    testing_logger::validate(|captured_logs| {
        let warnings = captured_logs
            .iter()
            .filter(|c| c.level == log::Level::Warn)
            .collect::<Vec<&testing_logger::CapturedLog>>();

        assert_eq!(warnings.len(), 1);
        assert_eq!(
            warnings[0].body,
            "Possible mistake.."
        );
    });
}

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.