Controlling How Tests Are Run
Just as cargo run compiles and runs your code, cargo test compiles your code in test mode and runs the resulting test binary. The default behavior is to run all tests in parallel and capture output. You can customize this behavior with command line options.
Command Line Options
Some options go to cargo test, and some go to the test binary. To separate them, use --:
cargo test --help # Options for cargo test
cargo test -- --help # Options for the test binary
Running Tests in Parallel or Consecutively
By default, tests run in parallel using threads. This makes tests complete faster but means they should not depend on each other or share mutable state.
If your tests depend on shared state, run them consecutively:
cargo test -- --test-threads=1
This sets the number of test threads to 1, running tests one at a time.
Showing Function Output
By default, successful tests capture any println! output. If a test passes, you won't see its printed output. Only failing tests show their output.
To see output from passing tests:
cargo test -- --show-output
Example:
fn printsAndReturnsValue(a: Int): Int {
println!("I got the value \(a)")
a
}
#[cfg(test)]
module tests {
import super.*
#[test]
fn thisPasses() {
let value = printsAndReturnsValue(4)
assertEq!(value, 4)
}
#[test]
fn thisFails() {
let value = printsAndReturnsValue(8)
assertEq!(value, 5)
}
}
Running cargo test:
running 2 tests
test tests.thisPasses ... ok
test tests.thisFails ... FAILED
failures:
---- tests.thisFails stdout ----
I got the value 8
thread 'tests.thisFails' panicked at src/lib.ox:17:9:
assertion `left == right` failed
left: 8
right: 5
Notice only the failing test shows its println! output.
Running cargo test -- --show-output:
running 2 tests
test tests.thisFails ... FAILED
test tests.thisPasses ... ok
successes:
---- tests.thisPasses stdout ----
I got the value 4
successes:
tests.thisPasses
failures:
---- tests.thisFails stdout ----
I got the value 8
thread 'tests.thisFails' panicked at src/lib.ox:17:9:
assertion `left == right` failed
left: 8
right: 5
Now both tests show their output.
Running a Subset of Tests by Name
Running the full test suite takes time. You can run specific tests by name.
Running Single Tests
Pass the test name to cargo test:
cargo test thisPasses
Output:
running 1 test
test tests.thisPasses ... ok
test result: ok. 1 passed; 0 filtered out
Note: You can use either the Oxide camelCase name (thisPasses) or the Rust snake_case name (this_passes).
Filtering to Run Multiple Tests
Specify part of a test name to run all matching tests:
public fn addTwo(a: Int): Int {
a + 2
}
#[cfg(test)]
module tests {
import super.*
#[test]
fn addTwoAndTwo() {
assertEq!(4, addTwo(2))
}
#[test]
fn addThreeAndTwo() {
assertEq!(5, addTwo(3))
}
#[test]
fn oneHundred() {
assertEq!(102, addTwo(100))
}
}
Running all tests:
cargo test
running 3 tests
test tests.addThreeAndTwo ... ok
test tests.addTwoAndTwo ... ok
test tests.oneHundred ... ok
Running only the "add" tests:
cargo test add
running 2 tests
test tests.addThreeAndTwo ... ok
test tests.addTwoAndTwo ... ok
Running Tests by Module Name
You can also filter by module name:
cargo test tests::
This runs all tests in the tests module.
Ignoring Tests Unless Specifically Requested
Some tests are expensive and you want to skip them in normal runs. Use the #[ignore] attribute:
#[cfg(test)]
module tests {
#[test]
fn itWorks() {
assertEq!(2 + 2, 4)
}
#[test]
#[ignore]
fn expensiveTest() {
// This test takes a long time to run
// Code that takes an hour to run...
}
}
Running cargo test:
running 2 tests
test tests.expensiveTest ... ignored
test tests.itWorks ... ok
test result: ok. 1 passed; 0 failed; 1 ignored
To run only the ignored tests:
cargo test -- --ignored
To run all tests including ignored ones:
cargo test -- --include-ignored
Running Tests by Type
Cargo can run different types of tests:
cargo test --lib # Run library tests only
cargo test --doc # Run documentation tests only
cargo test --bins # Run binary tests only
cargo test --tests # Run integration tests only
Running a Specific Test File
For integration tests, run tests from a specific file:
cargo test --test integration_test
This runs tests only from tests/integration_test.rs (or tests/integration_test.ox).
Useful Test Options
Here are commonly used test options:
| Option | Description |
|---|---|
--test-threads=N | Number of parallel test threads |
--show-output | Show output from passing tests |
--ignored | Run only ignored tests |
--include-ignored | Run all tests including ignored |
--nocapture | Don't capture output (same as --show-output) |
--test NAME | Run a specific test binary |
--exact | Match test name exactly |
--skip PATTERN | Skip tests matching pattern |
Exact Matching
By default, test name matching is a substring match. For exact matching:
cargo test thisPasses -- --exact
Skipping Tests
Skip tests matching a pattern:
cargo test -- --skip expensive
Summary
- Use
cargo testto run all tests - Add
--to pass options to the test binary - Control parallelism with
--test-threads - See output with
--show-output - Filter tests by name with
cargo test <pattern> - Use
#[ignore]for expensive tests - Run ignored tests with
--ignored - Use
--exactfor exact name matching - Skip patterns with
--skip
The next section covers how to organize your tests into unit tests and integration tests.