From the testing chapters linked above, we see how to write unit tests and integration tests. Organizationally, we can place unit tests in the modules they test and integration tests in their own tests/ directory:
foo
├── Cargo.toml
├── src
│ └── main.rs
└── tests
├── my_test.rs
└── my_other_test.rs
Each file in tests is a separate integration test.
cargo naturally provides an easy way to run all of your tests!
$ cargo test
You should see output like this:
$ cargo test
Compiling blah v0.1.0 (file:///nobackup/blah)
Finished dev [unoptimized + debuginfo] target(s) in 0.89 secs
Running target/debug/deps/blah-d3b32b97275ec472
running 3 tests
test test_bar ... ok
test test_baz ... ok
test test_foo_bar ... ok
test test_foo ... ok
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
You can also run tests whose name matches a pattern:
$ cargo test test_foo
$ cargo test test_foo
Compiling blah v0.1.0 (file:///nobackup/blah)
Finished dev [unoptimized + debuginfo] target(s) in 0.35 secs
Running target/debug/deps/blah-d3b32b97275ec472
running 2 tests
test test_foo ... ok
test test_foo_bar ... ok
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out
One word of caution: Cargo may run multiple tests concurrently, so make sure that they don't race with each other. For example, if they all output to a file, you should make them write to different files.
Sometimes a normal build from cargo is not enough. Perhaps your crate needs some pre-requisites before cargo will successfully compile, things like code generation, or some native code that needs to be compiled. To solve this problem we have build scripts that Cargo can run.
To add a build script to your package it can either be specified in the Cargo.toml as follows:
[package]
...
build = "build.rs"
Otherwise Cargo will look for a build.rs file in the project directory by default.
The build script is simply another Rust file that will be compiled and invoked prior to compiling anything else in the package. Hence it can be used to fulfill pre-requisites of your crate.
Cargo provides the script with inputs via environment variables specified here that can be used.
The script provides output via stdout. All lines printed are written to target/debug/build/
For further specification and examples have a read of the Cargo specification.
An attribute is metadata applied to some module, crate or item. This metadata can be used to/for:
• conditional compilation of code
• set crate name, version and type (binary or library)
• disable lints (warnings)
• enable compiler features (macros, glob imports, etc.)
• link to a foreign library
• mark functions as unit tests
• mark functions that will be part of a benchmark
When attributes apply to a whole crate, their syntax is #![crate_attribute], and when they apply to a module or item, the syntax is #[item_attribute] (notice the missing bang !).
Attributes can take arguments with different syntaxes:
• #[attribute = "value"]
• #[attribute(key = "value")]
• #[attribute(value)]
Attributes can have multiple values and can be separated over multiple lines, too:
#[attribute(value, value2)]
#[attribute(value, value2, value3,
value4, value5)]
The compiler provides a dead_code
fn used_function() {}
// `#[allow(dead_code)]` is an attribute that disables the `dead_code` lint
#[allow(dead_code)]
fn unused_function() {}