Unit testing in Rust is built into the language itself through built-in macros, special attributes, and the cargo infrastructure. Historically, in C and several other languages, testing is an external overlay, which leads to a discrepancy between the production code interface and the tests. In Rust, tests are compiled and run in the same environment as the main code, eliminating the problem of "works only in tests".
Problem: Tests can slow down builds, be uninformative, or poorly organized; also, poorly isolated tests hinder code maintenance and readability.
Solution: Tests are written as special functions marked with the #[test] attribute inside a module mod tests. All test code is compiled and run only with the cargo test key; it is excluded from the production build. Macros like assert_eq!, should_panic, and setup methods are used to enhance the efficiency and cleanliness of testing.
Example code:
pub fn add(a: i32, b: i32) -> i32 { a + b } #[cfg(test)] mod tests { use super::*; #[test] fn test_add() { assert_eq!(add(2, 2), 4); } }
Key features:
cargo test, and do not appear in the release binaryIs it mandatory to place tests only in the nested module mod tests?
Not necessarily, but it is common for the isolation of tests and preventing leakage of test code into release. It also helps to use #[cfg(test)].
Can tests be run only on a specific module/file?
Yes, you can specify the test name or path to it using cargo test name.
Are private functions tested?
Yes, if the test module is defined within the same file and uses use super::*;, the tests have access to all internal functions of the file.
Tests are mixed with the main code, not hidden in #[cfg(test)], and use global variables for initialization.
Pros:
Cons:
Tests are encapsulated in nested modules, using setup functions and assert_eq! macros for verification.
Pros:
Cons: