Testing in Rust: Frameworks and Tools
Rust is a systems programming language that places a huge emphasis on reliability and safety. Its built-in testing system is one of the key features, allowing you to write quality code without needing to install third-party frameworks. In this article, we will take a detailed look at the main tools for testing in Rust: from simple unit tests to complex property-based tests and benchmarks.
Built-in Testing Framework
In Rust, tests are run using the cargo test command. Tests are regular functions marked with the #[test] attribute. The framework automatically collects all such functions in your project and runs them.
Unit Tests
Unit tests are usually located in the same file as the code being tested, in a separate tests module. This allows testing private functions.
// src/lib.rspub fn add(a: i32, b: i32) -> i32 { a + b}
fn private_helper(x: i32) -> i32 { x * 2}
#[cfg(test)]mod tests { use super::*;
#[test] fn test_add() { assert_eq!(add(2, 3), 5); }
#[test] fn test_private_helper() { assert_eq!(private_helper(5), 10); }}Run: cargo test
Integration Tests
Integration tests are located in the tests/ directory at the project root level. Each file in this folder is a separate crate that tests your public API.
// tests/integration_test.rsuse my_crate::add;
#[test]fn test_add_integration() { assert_eq!(add(10, 20), 30);}Assertion Macros
Rust provides several built-in macros for writing assertions:
assert!(expression)— panics if the expression is false.assert_eq!(left, right)— checks equality usingPartialEq.assert_ne!(left, right)— checks inequality.debug_assert!()— works only in debug builds.
#[test]fn test_with_assert() { let result = some_function(); assert!(result.is_ok(), "Expected Ok, got: {:?}", result); assert_eq!(result.unwrap(), 42);}Doctests
One of Rust's most powerful features is the ability to write tests directly in the documentation. Code inside /// or //! blocks is automatically compiled and run as a test.
/// Adds two numbers.////// # Examples////// ```/// use my_crate::add;/// assert_eq!(add(1, 2), 3);/// ```pub fn add(a: i32, b: i32) -> i32 { a + b}Run: cargo test — doctests will run alongside regular tests.
Property-based Testing with proptest
The proptest library (analogous to Hypothesis in Python or QuickCheck in Haskell) allows you to generate random input data and check invariants.
use proptest::prelude::*;
fn reverse_string(s: &str) -> String { s.chars().rev().collect()}
proptest! { #[test] fn test_reverse_twice(s in ".*") { let reversed = reverse_string(&s); let double_reversed = reverse_string(&reversed); assert_eq!(s, double_reversed); }}Installation: cargo add proptest
Benchmarks
For performance measurement in Rust, there are stable benchmarks (starting from Rust 1.78) via cargo bench and the criterion crate for more complex scenarios.
Built-in Benchmarks (nightly)
#![feature(test)]extern crate test;
#[bench]fn bench_add(b: &mut test::Bencher) { b.iter(|| add(1, 2));}Benchmarks with criterion
Also in library
Recommendations