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
Top comments (0)