liveBook · Manning

Test

As explained in Learn Rust in a Month of Lunches

A test function is a Rust function executed by the test framework to check program behavior and normally takes no arguments.

Rust’s compiler catches many problems, but it cannot tell whether your program does what you intended. Tests check that behavior and can alert you when a later change breaks it. A test function is a function marked with `#[test]`; it takes no arguments. section 14.0 section 14.2.1

#[test]
fn two_is_two() {
    assert_eq!(2, 2);
}

This small test compares two values with `assert_eq!`. Because they match, the test passes. section 14.2.1

Run tests with the Playground’s Test button, not Run, or use `cargo test` if Rust is installed. You do not need a `main()` function. A test passes if it does not panic and fails if it does. For example, `assert_eq!(2, 3)` panics because the values differ; `assert!(2 == 3)` also fails. section 14.2.1 section 14.2.2

A failure report names the test and shows where it panicked. With `assert_eq!`, it also shows the left and right values—useful clues when the result surprises you. If the location is hard to find, enabling `RUST_BACKTRACE=1` gives more detail; you need not read the whole backtrace to find the line in your code. section 14.2.2

running 1 test
test two_is_two ... FAILED
 
failures:
 
---- two_is_two stdout ----
thread 'two_is_two' panicked at src/lib.rs:3:5:
assertion `left == right` failed
  left: 2
 right: 3
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 
 
failures:
    two_is_two
 
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered
out; finished in 0.00s

Compare the test name, panic location, and unequal values in this failed run. section 14.2.2

You can keep several tests beside the functions they check. A common arrangement puts them in a `mod tests` block marked `#[cfg(test)]`, so that module is compiled only when testing. Each test still needs its own `#[test]`. Inside the module, `use super::*;` gives the tests access to functions above it. section 14.2 section 14.2.3

fn return_two() -> i8 {
    2
}
fn return_six() -> i8 {
    4 + return_two()
}
 
#[cfg(test)]
mod tests {
    use super::*;
 
    #[test]
    fn it_returns_six() {
        assert_eq!(return_six(), 6)
    }
    #[test]
    fn it_returns_two() {
        assert_eq!(return_two(), 2);
    }
}

The two tests live beside the functions they check, inside a module compiled for testing. section 14.2.3

You can also write tests *before* the code, an approach called test-driven development (TDD). First describe the behavior you want in tests, then implement it until they pass. For a subtraction calculator, tests can check ordinary subtraction, double minus signs, trailing characters, and invalid input that should panic. Descriptive names make failures easier to recognize. As the calculator develops, a newly passing test shows progress, while a parsing error in another test points to the next fix. The tests remain useful after the code changes again. section 14.3.1 section 14.3.2 section 14.3

How Learn Rust in a Month of Lunches covers it

How deep it goes
Works through assertions, failure output, test modules, and test-first iterations; defers fuller treatment of environment variables.
Examples
Uses a two-value assertion, tests of small arithmetic functions, and a subtraction calculator with invalid-input cases.
What it assumes
Assumes familiarity with functions and modules while introducing `#[test]` and test execution from a minimal example.
What you can do after
Apply it via `cargo test` or the Playground’s Test button to run tests and use failures to guide fixes.
How it connects
Connects tests to modules, conditional compilation, panics, backtraces, and test-driven development.

Also explained in

Compare how 53 books explain test →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Learn Rust in a Month of Lunches. The section links point to the parts of the book it draws on.