back

How to test println!

Let’s say we want to test that a function is correctly outputting something.

Our function may looks like this simple example: print n times the name given in parameter.

fn greeting(nb: i32, name: &str) {
    for _ in 0..nb {
        println!("hi {}", name);
    }   
}

How to test it? 🤔 It looks hard.

One easy way is to refactor our code using a Trait. You can see Traits as interfaces.

trait Logger {
    fn log(&mut self, value: String);
}

Then, let’s define a struct which implements this trait.

struct ConsoleLogger;

impl Logger for ConsoleLogger {
    fn log(&mut self, value: String) {
        println!("{}", value);
    }
}

Great! Now we can refactor our greeting function to use this trait.

fn greeting(nb: i32, name: &str, logger: &mut dyn Logger) {
    for _ in 0..nb {
        logger.log(format!("hi {}", name));
    }
}

Ok but how this is helpful for testing?

Well, now, in tests, we could define a new struct with a different implementation for our trait.

Here, instead of outputting our strings using println! we will store those in a Vec<String> This way, it will be super easy to assert that our values are valid.

struct TestLogger(Vec<String>);

impl Logger for TestLogger {
        fn log(&mut self, value: String) {
            self.0.push(value);
        }
}

And we can finally test:

#[test]
fn greeting_test() {
    let mut test_logger = TestLogger::default();
    greeting(2, "maxday", &mut test_logger);
    assert_eq!(2, test_logger.0.len());
    assert_eq!("hi maxday", test_logger.0[0]);
    assert_eq!("hi maxday", test_logger.0[1]);
}

Voila! 🎉

Full code here: https://gist.github.com/maxday/ae3c9f219c35c228dadd5359def5a833

🚀 🚀 🚀 If you want more Rust, feel free to check my new YouTube channel here: https://youtube.com/@maxday_coding