DEV Community

Cover image for Tests Everywhere - Rust
Roger Viñas Alcon
Roger Viñas Alcon

Posted on • Edited on

Tests Everywhere - Rust

GitHub logo rogervinas / tests-everywhere

🤠 Tests, Tests Everywhere!

Rust testing this simple Hello World with mockall

Show me the code

Implementation

  1. Create HelloMessage trait and HelloWorldMessage implementation in hello_message.rs:
pub trait HelloMessage { fn text(&self) -> String; } pub struct HelloWorldMessage {} impl HelloMessage for HelloWorldMessage { fn text(&self) -> String { return String::from("Hello World!"); } } impl HelloWorldMessage { pub fn new() -> Self { Self {} } } 
Enter fullscreen mode Exit fullscreen mode

Creating it as a trait will allow us to mock it for testing.

Note that we create a HelloWorldMessage::new() method just as a convention to create new instances, although we could just use HelloWorldMessage {}.

  1. Same way create HelloConsole trait and HelloSystemConsole implementation in hello_console.rs:
pub trait HelloConsole { fn print(&self, text: String); } pub struct HelloSystemConsole {} impl HelloConsole for HelloSystemConsole { fn print(&self, text: String) { println!("{}", text); } } impl HelloSystemConsole { pub fn new() -> Self { Self {} } } 
Enter fullscreen mode Exit fullscreen mode
  1. Create HelloApp class in hello_app.rs:
pub struct HelloApp { message: Box<dyn HelloMessage>, console: Box<dyn HelloConsole> } impl HelloApp { pub fn new(message: Box<dyn HelloMessage>, console: Box<dyn HelloConsole>) -> Self { Self { message, console } } pub fn print_hello(&self) { self.console.print(self.message.text()); } } 
Enter fullscreen mode Exit fullscreen mode

Note that we pass constructor arguments as Box<dyn T> to avoid doesn't have a size known at compile-time compilation error.

  1. Create main function in main.rs that wraps it all together:
fn main() { let message = HelloWorldMessage::new(); let console = HelloSystemConsole::new(); let app = HelloApp::new(Box::new(message), Box::new(console)); app.print_hello(); } 
Enter fullscreen mode Exit fullscreen mode

Test

Following Rust By Example > Unit testing and mockall > Getting Started guides ...

  1. Test HelloMessage in hello_message.rs:
#[cfg(test)] mod tests { use super::*; #[test] fn should_return_hello_world() { let message = HelloWorldMessage::new(); assert_eq!(message.text(), String::from("Hello World!")) } } 
Enter fullscreen mode Exit fullscreen mode
  1. Setup HelloMessage mocking needed by HelloApp test in hello_message.rs:
// 2.1 Enable automock #[cfg(test)] use mockall::automock; // 2.2 Enable automock for HelloMessage #[cfg_attr(test, automock)] pub trait HelloMessage { fn text(&self) -> String; } 
Enter fullscreen mode Exit fullscreen mode
  1. Setup HelloConsole mocking needed by HelloApp test in hello_console.rs:
// 3.1 Enable automock #[cfg(test)] use mockall::automock; // 3.2 Enable automock for HelloConsole #[cfg_attr(test, automock)] pub trait HelloConsole { fn print(&self, text: String); } 
Enter fullscreen mode Exit fullscreen mode
  1. Test HelloApp in hello_app.rs:
#[cfg(test)] mod tests { use super::*; use mockall::predicate::*; // 4.1 Use MockHelloMessage, enabled by 2.2 use crate::hello_message::MockHelloMessage; // 4.2 Use MockHelloConsole, enabled by 3.2 use crate::hello_console::MockHelloConsole; #[test] fn should_print_hello_message() { let message_text = "Hello Test!"; // 4.3 Create a mock of HelloMessage let mut message = MockHelloMessage::new(); // 4.4 Return "Hello Test!" whenever text is called message.expect_text().return_const(String::from(message_text)); // 4.5 Create a mock of HelloConsole let mut console = MockHelloConsole::new(); // 4.6 Expect print to be called once with "Hello Test!" console.expect_print() .with(eq(String::from(message_text))) .times(1) .return_const(()); // 4.7 Create a HelloApp, the one we want to test, passing the mocks let app = HelloApp::new(Box::new(message), Box::new(console)); // 4.8 Execute the method we want to test app.print_hello(); // Expectation 4.6 will be checked once test ends } } 
Enter fullscreen mode Exit fullscreen mode
  1. Test output should look like:
running 2 tests test hello_app::tests::should_print_hello_message ... ok test hello_message::tests::should_return_hello_world ... ok test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s 
Enter fullscreen mode Exit fullscreen mode

Happy Testing! 💙

Top comments (0)