This document describes best practices for writing tests for Rust code. Please also refer to the components testing guide for instructions on defining test packages and components and running them.
This document is targeted towards developers working inside of fuchsia.git
,
and the workflow described is unlikely to work for IDK consumers.
The source code for this tutorial is available at
//examples/hello_world/rust
.
Unit tests
Adding tests to code
The idiomatic way for adding Rust unit tests works just as well inside of Fuchsia as it does outside, and can be easily accomplished by dropping the following snippet into the bottom of whatever test you want to write:
#[cfg(test)]
mod tests {
#[fuchsia::test]
fn it_works() {
assert_eq!(true, true);
}
}
This will cause a new mod named tests
to be created, and this mod will only be
included when building unit tests. Any functions annotated with
#[fuchsia::test]
will be run as a test, and if the function successfully
returns then the test passes.
#[fuchsia::test]
also supports tests exercising asynchronous code.
#[fuchsia::test]
async fn my_test() {
let some_future = async { 4 };
assert_eq!(some_future.await, 4);
}
The typical #[test]
annotation also works, but it doesn't support async tests
or logging out of the box. Prefer #[test]
in situations where you think the
crate might get used outside of the Fuchsia codebase.
Building tests
The unit tests can be automatically built by Rust targets (i.e. either
rustc_binary
or rustc_library
). The approaches are by and large similar.
Building tests for a Rust binary
This section is useful if you are testing a rust binary (i.e. you have a
main.rs
). If you have a library instead, see the next section.
Your BUILD.gn
file first needs to make available the rustc_binary
template
by importing it:
import("//build/rust/rustc_binary.gni")
Unit tests are built by the rustc_binary
GN template only if the setting
with_unit_tests = true
is added:
rustc_binary("bin") {
name = "hello_world_rust"
# Generates the "bin_test" build target
with_unit_tests = true
edition = "2021"
deps = []
test_deps = [ "//src/lib/fuchsia" ]
sources = [ "src/main.rs" ]
}
Setting with_unit_tests = true
causes this build rule to generate two
different executables, one with the provided and one with _bin_test
appended
to the provided name.
In our example here, the executable names that are created are called:
hello_world_rust
; andhello_world_rust_bin_test
.
Building tests for a Rust library
Your BUILD.gn
file first needs to make available the rustc_library
template
by importing it:
import("//build/rust/rustc_library.gni")
Unit tests are built by the rustc_library
GN template only if the setting
with_unit_tests = true
is added, similarly to how it is done in the case
of rustc_binary
above.
In this case, however, a differently named test binary is created:
hello_world_rust_lib_test
. Note that the name of the binary is different from the name generated by the library.
The binary names are important because they will be used in followup steps.
Packaging and running tests
To run the tests that were generated by previous targets, package them as test components. Test components contain a component manifest that declares the capabilities required by your tests. You can package tests using the following build rules:
fuchsia_test_package()
: Package template that collects multiple test components and their dependencies together in a single package. Test packages are typically used for integration tests.fuchsia_unittest_package()
: Specialized template for packages containing unit tests. Unit test packages can generate a minimal component manifest for unit tests with no required capabilities.
For the Hello World binary example, the unit test package references the
generated targets, bin_test
(based on target name bin
and the implicit
suffix _test
), and hello_world_rust_bin_test
(based on the value of name
stanza).
fuchsia_unittest_package("hello-world-rust-tests") {
deps = [ ":bin_test" ]
}
To run the tests run:
fx test hello-world-rust-tests
For information on packaging and running tests, see test components and building components.
Helpful crates
The following in-tree third-party crates can help you write tests:
assert_matches
: provides the macroassert_matches!
, making pattern assertions ergonomic.pretty_assertions
: provides an alternativeassert_eq!
macro that displays a colored diff when the assertion fails.
These can be included in your BUILD.gn
under test_deps
.
rustc_binary("bin") {
name = "my_test"
with_unit_tests = true
edition = "2021"
test_deps = [
"//third_party/rust_crates:matches",
"//third_party/rust_crates:pretty_assertions",
]
}