Rust 46 ๐ฆ Writing Automated Unit Tests and Documentation Tests
Rust treats testing as a first-class part of the language. The cargo test command is built into the toolchain, the test functions are ordinary functions annotated with the #[test] attribute, and the test module is the ordinary module with the #[cfg(test)] attribute. There is no separate test framework to install, no configuration file to write, and no test runner to configure. The cargo test discovers the test functions, runs them in parallel, captures the output, and reports the results. The testing is the part of the language, and the cargo test is the command that runs it.
The unit tests live in the same file as the code they test. The convention is the #[cfg(test)] mod tests module at the bottom of the file, and the use super::* imports the parent module’s items. The #[cfg(test)] attribute tells the compiler to include the module only in the test build, so the test code does not ship in the release binary. The #[test] attribute marks the test function, and the function passes when it returns and fails when it panics. The assert!, the assert_eq!, and the assert_ne! macros are the assertions, and the #[should_panic] attribute marks the test that must panic.
The integration tests live in the tests directory, and each file is a separate crate that uses the library as the external consumer. The documentation tests live in the doc comments, and the cargo test runs the code examples in the /// comments. The three kinds of tests โ the unit, the integration, and the documentation โ form the testing strategy, and the cargo test runs all of them. The #[ignore] attribute skips the expensive tests, and the cargo test -- --ignored runs them.
This chapter covers three areas. First, why the Rust testing exists โ the built-in testing and the test-as-code. Second, the unit tests โ the #[cfg(test)], the #[test], the assertions, the #[should_panic], the Result return, and the private function testing. Third, the integration and the documentation tests โ the tests directory, the doc comments, the cargo test --doc, and the test organization. The chapter ends with a complete example session, a quick reference, best practices, common pitfalls, real-world examples, and diagrams showing the test organization.
Key point: The Rust testing is built into the language. The #[cfg(test)] module contains the unit tests, the #[test] attribute marks the test functions, and the cargo test runs them. The assert!, the assert_eq!, and the assert_ne! macros are the assertions. The #[should_panic] marks the tests that must panic, and the Result<(), E> return allows the ? operator. The integration tests live in the tests directory, and the documentation tests live in the doc comments.
Why the Rust testing exists
The built-in testing problem. The other languages require the separate test framework: the JUnit for the Java, the pytest for the Python, the Jest for the JavaScript. The Rust includes the testing in the toolchain, and the cargo test is the command. There is no dependency to add, no configuration to write, and no version to manage. The testing is the language feature, and the cargo test is the entry point.
The test-as-code problem. The Rust tests are the ordinary functions with the #[test] attribute. They live in the same module as the code, they use the same syntax, and they compile with the same compiler. The developer does not learn a new framework; the developer writes the functions. The test is the code, and the code is the test.
The private-function problem. The Rust unit tests can test the private functions, because the #[cfg(test)] mod tests is the child module, and the child modules can access the private items of the parent. The integration tests in the tests directory can only test the public API, because they are the external crates. The two kinds of tests cover the different levels, and the unit tests are the white-box, and the integration tests are the black-box.
The documentation problem. The documentation tests are the code examples in the doc comments. The cargo test extracts the examples, compiles them, and runs them. The example is the documentation and the test at the same time. The documentation that does not compile fails the test, and the example that does not work fails the test. The documentation is verified, and the example is the tested.
The cargo test output problem. The cargo test runs the tests in parallel, captures the output, and reports the pass and the fail. The --test-threads controls the parallelism, the --nocapture shows the output, the --ignored runs the ignored tests, and the --doc runs only the documentation tests. The command is the tool, and the flags are the control.
The trade-off. The Rust testing is the simple and the built-in, and the test organization is the convention. The unit tests in the same file are the convenient and the clutter. The integration tests in the separate directory are the clean and the public-API-only. The documentation tests are the free but require the well-written examples. The trade-off is between the convenience and the organization, and the conventions are the guide.
a. The unit tests
The unit tests live in the same file as the code, in the #[cfg(test)] mod tests module.
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_adds() {
assert_eq!(add(2, 3), 5);
}
#[test]
fn it_handles_the_negatives() {
assert_eq!(add(-2, -3), -5);
}
}
The #[cfg(test)] includes the module only in the test build. The use super::* imports the parent module’s items, so the test can call the add function. The #[test] marks the test function, and the assert_eq! is the assertion .
The cargo test runs the tests:
cargo test
The output:
running 2 tests
test tests::it_adds ... ok
test tests::it_handles_the_negatives ... ok
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
The assertions. The assert! takes the boolean, and the assert_eq! and the assert_ne! take the two values:
#[test]
fn it_asserts() {
assert!(true);
assert_eq!(2 + 2, 4);
assert_ne!(2 + 2, 5);
}
The macros accept the custom message as the additional argument:
assert_eq!(add(2, 3), 5, "the addition of the 2 and the 3 should be the 5");
The #[should_panic]. The test that must panic:
pub fn divide(a: i32, b: i32) -> i32 {
if b == 0 {
panic!("the divisor cannot be the zero");
}
a / b
}
#[test]
#[should_panic(expected = "the divisor cannot be the zero")]
fn it_panics_on_the_zero() {
divide(10, 0);
}
The #[should_panic] passes when the test panics, and the expected checks the panic message contains the substring .
The Result return. The test can return the Result<(), E>, and the ? operator works:
#[test]
fn it_parses() -> Result<(), Box<dyn std::error::Error>> {
let value: i32 = "42".parse()?;
assert_eq!(value, 42);
Ok(())
}
The test passes when the Result is the Ok, and fails when it is the Err. The Result return is the modern, and the #[should_panic] is the legacy for the panic .
The private function testing. The unit test can test the private functions:
fn internal_add(a: i32, b: i32) -> i32 {
a + b
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_tests_the_private() {
assert_eq!(internal_add(2, 3), 5);
}
}
The internal_add is private, and the test module can access it because the child module can see the parent’s private items .
The #[ignore]. The expensive test is ignored by default:
#[test]
#[ignore = "the test is the slow"]
fn it_is_the_slow() {
// the expensive setup
}
The cargo test skips the ignored, and the cargo test -- --ignored runs them .
b. The integration tests
The integration tests live in the tests directory, and each file is a separate crate. The test uses the library as the external consumer, and it can only access the public API.
my_project/
โโโ src/
โ โโโ lib.rs
โโโ tests/
โ โโโ integration_test.rs
โโโ Cargo.toml
The integration test:
// tests/integration_test.rs
use my_project::add;
#[test]
fn it_adds_from_the_outside() {
assert_eq!(add(2, 3), 5);
}
The use my_project::add imports the public function from the library. The integration test cannot access the private items, because it is the external crate .
The cargo test runs the integration tests:
running 1 test
test it_adds_from_the_outside ... ok
The output shows the unit tests, the integration tests, and the documentation tests in the separate sections .
The shared test utilities. The tests/common/mod.rs is the shared module for the integration tests:
// tests/common/mod.rs
pub fn setup() -> TestContext {
TestContext::new()
}
The test file uses the module:
// tests/integration_test.rs
mod common;
#[test]
fn it_uses_the_setup() {
let context = common::setup();
// ...
}
The common is the subdirectory with the mod.rs, and the cargo test does not treat the common/mod.rs as the separate test file .
c. The documentation tests
The documentation tests are the code examples in the doc comments. The cargo test extracts them, compiles them, and runs them.
/// The adds the two numbers.
///
/// # Examples
///
/// ```
/// let result = my_project::add(2, 3);
/// assert_eq!(result, 5);
/// ```
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
The triple-backtick block is the code example. The cargo test runs the example as the test, and the example fails when the assertion fails. The documentation and the test are the same .
The no_run attribute. The example that compiles but does not run:
/// ```no_run
/// let listener = std::net::TcpListener::bind("127.0.0.1:8080").unwrap();
/// ```
The no_run compiles the example but does not run it, and the ignore skips it entirely. The should_panic expects the panic, and the compile_fail expects the compile failure .
The ? operator in the example. The example with the ? needs the Result return:
/// ```
/// use std::error::Error;
/// fn main() -> Result<(), Box<dyn Error>> {
/// let value: i32 = "42".parse()?;
/// assert_eq!(value, 42);
/// Ok(())
/// }
/// ```
The example with the ? must return the Result, and the main function is the standard wrapper .
The cargo test --doc runs only the documentation tests:
cargo test --doc
The command runs the documentation tests and skips the unit and the integration tests .
The documentation test hiding. The # at the line start hides the line from the documentation but includes it in the test:
/// ```
/// # fn main() -> Result<(), Box<dyn Error>> {
/// let value: i32 = "42".parse()?;
/// # Ok(())
/// # }
/// ```
The # lines are the boilerplate that the reader does not need to see, and the test includes them .
Complete Example Session
// ============================================
// PART 1: THE BASIC UNIT TEST
// ============================================
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_adds() {
assert_eq!(add(2, 3), 5);
}
}
// The cargo test runs the test.
// ============================================
// PART 2: THE ASSERTIONS
// ============================================
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_asserts() {
assert!(true);
assert_eq!(2 + 2, 4);
assert_ne!(2 + 2, 5);
}
#[test]
fn it_asserts_with_the_message() {
assert_eq!(add(2, 3), 5, "the 2 + the 3 should be the 5");
}
}
// ============================================
// PART 3: THE SHOULD_PANIC
// ============================================
pub fn divide(a: i32, b: i32) -> i32 {
if b == 0 {
panic!("the divisor cannot be the zero");
}
a / b
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[should_panic(expected = "the divisor cannot be the zero")]
fn it_panics_on_the_zero() {
divide(10, 0);
}
}
// ============================================
// PART 4: THE RESULT RETURN
// ============================================
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_parses() -> Result<(), Box<dyn std::error::Error>> {
let value: i32 = "42".parse()?;
assert_eq!(value, 42);
Ok(())
}
}
// ============================================
// PART 5: THE PRIVATE FUNCTION
// ============================================
fn internal_add(a: i32, b: i32) -> i32 {
a + b
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_tests_the_private() {
assert_eq!(internal_add(2, 3), 5);
}
}
// ============================================
// PART 6: THE IGNORE
// ============================================
#[cfg(test)]
mod tests {
#[test]
#[ignore = "the test is the slow"]
fn it_is_the_slow() {
// the expensive setup
}
}
// The cargo test skips the ignored.
// The cargo test -- --ignored runs them.
// ============================================
// PART 7: THE INTEGRATION TEST
// ============================================
// tests/integration_test.rs
use my_project::add;
#[test]
fn it_adds_from_the_outside() {
assert_eq!(add(2, 3), 5);
}
// The cargo test runs the integration tests.
// ============================================
// PART 8: THE SHARED TEST UTILITIES
// ============================================
// tests/common/mod.rs
pub fn setup() -> TestContext {
TestContext::new()
}
// tests/integration_test.rs
mod common;
#[test]
fn it_uses_the_setup() {
let context = common::setup();
// ...
}
// ============================================
// PART 9: THE DOCUMENTATION TEST
// ============================================
/// The adds the two numbers.
///
/// # Examples
///
/// ```
/// let result = my_project::add(2, 3);
/// assert_eq!(result, 5);
/// ```
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
// The cargo test runs the documentation tests.
// ============================================
// PART 10: THE COMPLETE EXAMPLE
// ============================================
pub struct Calculator {
memory: f64,
}
impl Calculator {
pub fn new() -> Self {
Calculator { memory: 0.0 }
}
pub fn add(&mut self, value: f64) -> f64 {
self.memory += value;
self.memory
}
pub fn divide(&mut self, value: f64) -> Result<f64, String> {
if value == 0.0 {
return Err("the division by the zero".to_string());
}
self.memory /= value;
Ok(self.memory)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_adds() {
let mut calc = Calculator::new();
assert_eq!(calc.add(5.0), 5.0);
assert_eq!(calc.add(3.0), 8.0);
}
#[test]
fn it_divides() {
let mut calc = Calculator::new();
calc.add(10.0);
assert_eq!(calc.divide(2.0), Ok(5.0));
}
#[test]
fn it_rejects_the_zero_division() {
let mut calc = Calculator::new();
calc.add(10.0);
assert!(calc.divide(0.0).is_err());
}
#[test]
#[should_panic(expected = "the overflow")]
fn it_panics_on_the_overflow() {
panic!("the overflow");
}
}
The ten parts show the basic unit test, the assertions, the #[should_panic], the Result return, the private function, the #[ignore], the integration test, the shared utilities, the documentation test, and the complete example.
Quick Reference
The Test Attributes
| The attribute | The purpose |
|---|---|
#[cfg(test)] | The test-only module |
#[test] | The test function |
#[should_panic] | The test must panic |
#[should_panic(expected = "...")] | The panic message |
#[ignore] | The skipped test |
#[ignore = "the reason"] | The skip reason |
The Assertion Macros
| The macro | The purpose |
|---|---|
assert!(condition) | The boolean |
assert!(condition, "msg") | The boolean with the message |
assert_eq!(a, b) | The equality |
assert_eq!(a, b, "msg") | The equality with the message |
assert_ne!(a, b) | The inequality |
The Test Commands
| The command | The purpose |
|---|---|
cargo test | Runs all the tests |
cargo test -- --nocapture | Shows the output |
cargo test -- --ignored | Runs the ignored |
cargo test -- --test-threads=1 | The single thread |
cargo test --doc | The documentation tests |
cargo test test_name | The specific test |
cargo test --lib | The unit tests only |
cargo test --test name | The integration test |
The Documentation Test Attributes
| The attribute | The purpose |
|---|---|
`` | The test that compiles and runs |
no_run | The compiles but does not run |
ignore | The skips |
should_panic | The expects the panic |
compile_fail | The expects the compile failure |
# | The hidden line |
The Test Organization
| The location | The access |
|---|---|
src/lib.rs (the #[cfg(test)]) | The private and the public |
tests/ | The public only |
| The doc comments | The public |
Best Practices
โ Do This:
// Use the #[cfg(test)] mod tests
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() { ... }
} // โ
// Use the assert_eq! with the message
assert_eq!(result, expected, "the result should be the expected"); // โ
// Use the #[should_panic] with the expected
#[should_panic(expected = "the error message")] // โ
// Use the Result return for the fallible tests
fn it_works() -> Result<(), Box<dyn Error>> { ... } // โ
// Use the doc examples
/// ```
/// assert_eq!(add(2, 3), 5);
/// ``` // โ
// Use the integration tests for the public API
// The tests/ directory // โ
โ Don’t Do This:
// Don't forget the #[cfg(test)]
mod tests { ... } // the test code in the release build // โ
// Don't use the unwrap in the test without the reason
let result = risky().unwrap(); // the unclear failure // โ
// Don't test the multiple things in one test
fn it_tests_everything() { ... } // the unclear // โ
// Don't use the #[should_panic] without the expected
#[should_panic] // the too broad // โ
// Don't put the unit tests in the tests/ directory
// The tests/ is the integration, the unit is the src/ // โ
// Don't forget the use super::*
mod tests { #[test] fn it() { add(2, 3); } } // the missing import // โ
Common Pitfalls
| The pitfall | The why | The fix |
|---|---|---|
| The test not found | The missing #[test] | Add the attribute |
| The import error | The missing use super::* | Add the import |
| The test in the release | The missing #[cfg(test)] | Add the attribute |
The should_panic passes on the wrong panic | The missing expected | Add the expected |
The ? does not compile | The missing Result return | Add the return type |
| The doc test fails | The wrong example | Fix the example |
| The integration test cannot access the private | The external crate | Use the unit test |
Real-World Examples
1. The Basic Test
#[test]
fn it_adds() {
assert_eq!(add(2, 3), 5);
}
2. The Should Panic
#[test]
#[should_panic(expected = "the zero")]
fn it_panics() {
divide(10, 0);
}
3. The Result Return
#[test]
fn it_parses() -> Result<(), Box<dyn Error>> {
let value: i32 = "42".parse()?;
Ok(())
}
4. The Ignore
#[test]
#[ignore = "the slow"]
fn it_is_the_slow() { }
5. The Private Test
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_tests_the_private() { ... }
}
6. The Integration Test
// tests/integration_test.rs
use my_project::add;
#[test]
fn it_adds() { assert_eq!(add(2, 3), 5); }
7. The Doc Test
/// ```
/// assert_eq!(add(2, 3), 5);
/// ```
8. The No Run
/// ```no_run
/// let listener = TcpListener::bind("...").unwrap();
/// ```
9. The Compile Fail
/// ```compile_fail
/// let x: i32 = "not a number";
/// ```
10. The Complete
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_adds() { assert_eq!(add(2, 3), 5); }
#[test]
#[should_panic(expected = "the zero")]
fn it_panics() { divide(10, 0); }
}
Visual
The Test Organization
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ THE TEST ORGANIZATION โ
โ โ
โ my_project/ โ
โ โโโ src/ โ
โ โ โโโ lib.rs โ
โ โ โโโ the public functions โ
โ โ โโโ the private functions โ
โ โ โโโ #[cfg(test)] mod tests { ... } โ the unit testsโ
โ โ โ
โ โโโ tests/ โ
โ โ โโโ integration_test.rs โ the integration tests โ
โ โ โโโ common/ โ
โ โ โโโ mod.rs โ the shared utilities โ
โ โ โ
โ โโโ Cargo.toml โ
โ โ
โ The cargo test runs: โ
โ 1. The unit tests (the src/) โ
โ 2. The integration tests (the tests/) โ
โ 3. The documentation tests (the doc comments) โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
The Test Flow
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ THE TEST FLOW โ
โ โ
โ cargo test โ
โ โ โ
โ โโโ The unit tests โ
โ โ The #[cfg(test)] modules in the src/ โ
โ โ The private and the public access โ
โ โ โ
โ โโโ The integration tests โ
โ โ The files in the tests/ โ
โ โ The public API only โ
โ โ โ
โ โโโ The documentation tests โ
โ The code examples in the /// comments โ
โ The public API only โ
โ โ โ
โ โผ โ
โ The output: โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ running 5 tests โ โ
โ โ test tests::it_adds ... ok โ โ
โ โ test tests::it_subtracts ... ok โ โ
โ โ test it_adds_from_the_outside ... ok โ โ
โ โ test src/lib.rs - add (line 5) ... ok โ โ
โ โ โ โ
โ โ test result: ok. 5 passed; 0 failed โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
The Assertion Macros
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ THE ASSERTION MACROS โ
โ โ
โ assert!(condition); โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ The passes when the condition is the true. โ โ
โ โ The fails when the condition is the false. โ โ
โ โ The panics with the message. โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ assert_eq!(a, b); โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ The passes when the a == the b. โ โ
โ โ The fails when the a != the b. โ โ
โ โ The message shows the a and the b. โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ assert_ne!(a, b); โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ The passes when the a != the b. โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ The macros require the Debug and the PartialEq. โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
The Documentation Test
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ THE DOCUMENTATION TEST โ
โ โ
โ /// The adds the two numbers. โ
โ /// โ
โ /// # Examples โ
โ /// โ
โ /// ``` โ
โ /// let result = my_project::add(2, 3); โ
โ /// assert_eq!(result, 5); โ
โ /// ``` โ
โ pub fn add(a: i32, b: i32) -> i32 { a + b } โ
โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ The cargo test extracts the example, compiles it, โ โ
โ โ and runs it. โ โ
โ โ โ โ
โ โ The example passes โ the doc test passes. โ โ
โ โ The example fails โ the doc test fails. โ โ
โ โ โ โ
โ โ The documentation and the test are the same. โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Summary
| Item | Value |
|---|---|
#[cfg(test)] | The test-only module |
#[test] | The test function |
assert! | The boolean assertion |
assert_eq! | The equality assertion |
assert_ne! | The inequality assertion |
#[should_panic] | The test must panic |
#[ignore] | The skipped test |
Result<(), E> | The fallible test return |
The tests/ directory | The integration tests |
| The doc comments | The documentation tests |
cargo test | The test runner |
Key takeaways:
- The Rust testing is built into the language. The
cargo testis the command, the#[test]is the attribute, and there is no separate framework to install. The testing is the language feature . - The unit tests live in the
#[cfg(test)] mod testsmodule. The module is included only in the test build, and theuse super::*imports the parent’s items. The unit tests can access the private functions . - The
assert!, theassert_eq!, and theassert_ne!are the assertions. The macros panic on the failure, and the panic message shows the values. The custom message is the additional argument . - The
#[should_panic]marks the test that must panic. Theexpectedattribute checks the panic message contains the substring. The test passes when the panic occurs . - The
Result<(), E>return allows the?operator. The test passes when theResultis theOk, and fails when it is theErr. TheResultreturn is the modern for the fallible tests . - The integration tests live in the
tests/directory. Each file is a separate crate, and the test can only access the public API. Thetests/common/mod.rsis the shared utilities . - The documentation tests are the code examples in the doc comments. The
cargo testextracts them, compiles them, and runs them. The documentation and the test are the same, and the example is the verified . - The
cargo testruns all three kinds of tests. The unit, the integration, and the documentation. The--docruns only the documentation, the--libruns only the unit, and the--ignoredruns the ignored .
Remember: The Rust testing is the built-in, the zero-dependency, and the first-class. The unit tests live in the #[cfg(test)] mod tests, the integration tests in the tests/ directory, and the documentation tests in the doc comments. The cargo test runs them all, and the assert!, the assert_eq!, and the assert_ne! are the assertions. The result is the tested code that ships with the confidence, which is the foundation of the reliable software.
Stop using slow, ad-bloated tool sites! ๐คฎ
๐ Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
โ
Finance (Mortgage, Interest, Inflation)
โ
Tech (Base64, JSON, Dev Suite, IP)
โ
Health (BMI, BMR, TDEE)
โ
Productivity (Timer, Workspace, QR)
โก๏ธ Fast & Private
๐ No data leaves your device
๐ 100% Free
๐ Use it now: https://tools.kandz.me
๐ Bookmark itโyouโll need it later!