Rust comes with a unit and integration test suit baked into cargo
. To make a function a test function, add #[test]
on the line before the function.
Tests in rust have access to the private parts of everything.
The following is an example of a unit test:
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn new(w: u32, h: u32) -> Rectangle {
Rectangle {width: w, height: h}
}
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
}
#[cfg(test)]
mod tests {
use super::*; // Brings outer module into scope
#[test]
fn larger_can_hold_smaller() {
let larger = Rectangle::new(5, 6);
let smaller = Rectangle::new(4, 5);
assert!(larger.can_hold(&smaller));
}
#[test]
fn smaller_cannot_hold_larget() {
let smaller = Rectangle::new(4, 5);
let larger = Rectangle::new(5, 6);
assert!(!smaller.can_hold(&larger));
}
#[test]
fn it_works() -> Result<(), String> {
if 2 + 2 == 4 {
Ok(())
} else {
Err(String::from("2 + 2 != 4"))
}
}
}
assert!(x)
: Passes if x
is trueassert_eq!(x, y)
: Passes if x
and y
are equalassert_ne!(x, y)
: Passes if x
and y
are not equalCustom failure messages are supported by the assert
family micros.
pub fn concat(fname: &str, lname: &str) -> String {
format!("{} {}", fname, lname)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn combine_names() {
let full_name = concat("Daltie", "Colti");
assert_eq!(
full_name,
"Daltie Coltie",
"Daltie Coltie != {}",
full_name
) // The same failure message logic can be applied to any assert! micro
}
}
Integration tests are external to your library. They can only call your library's public API.
Integration tests are only for library crates. For binary crates, only unit tests can be used.
Integration tests go inside of a tests directory next to your src directory. Example:
// src/lib.rs in crate addr
pub fn add_two(x: i32) -> i32 {
x + 2
}
// tests/integration_tests.rs
use addr;
#[test]
fn it_adds_two() {
assert_eq!(4, addr::add_two(2));
}
Each file in the tests directory is compiled as its own separate crate. To prevent this, put code you don't want separately tested into subdirectories inside of tests. These subdirectories will not be tested, but can act as support code for your tests.
If a test should panic, add #[should_panic]
before the function declaration.
#[test]
#[should_panic]
fn this_should_panic() {
panic_function(1000);
}
Unit tests are used to test how your code interacts with itself, testing one module in isolation at a time.
Unit tests live along side your code in the src directory in the same file as the code that it is testing. To create a unit test, create a module called tests
with the #[cfg(test)]
annotation. "cfg" stands for configuration.
Unit tests can test the private parts of your code.