blob: 556f745e60c0765152bdab73ebaea142e0cc70eb [file] [log] [blame] [view]
# Testing Rust code
This document describes best practices for writing tests for Rust code.
Please also refer to the [components testing guide][component-tests] 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`][example-src].
## 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:
```rust
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/hello_world/rust/src/main.rs" region_tag="test_mod" adjust_indentation="auto" %}
```
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.
```rust
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/hello_world/rust/src/main.rs" region_tag="async_test" adjust_indentation="auto" %}
```
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:
```gn
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:
```gn
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/hello_world/rust/BUILD.gn" region_tag="rustc_tests" adjust_indentation="auto" %}
```
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`; and
* `hello_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:
```gn
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][glossary.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).
```gn
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/hello_world/rust/BUILD.gn" region_tag="fuchsia_test" adjust_indentation="auto" %}
```
To run the tests run:
```posix-terminal
fx test hello-world-rust-tests
```
For information on packaging and running tests, see
[test components][component-tests] and [building components][build-tests].
### Helpful crates
The following in-tree third-party crates can help you write tests:
* [`assert_matches`]: provides the macro `assert_matches!`, making pattern
assertions ergonomic.
* [`pretty_assertions`]: provides an alternative `assert_eq!` macro that
displays a colored diff when the assertion fails.
These can be included in your `BUILD.gn` under `test_deps`.
```gn
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",
]
}
```
[build-tests]:/docs/development/components/build.md#test-packages
[component-tests]:/docs/development/testing/components/test_component.md
[example-src]: /examples/hello_world/rust
[glossary.component-manifest]: /docs/glossary/README.md#component-manifest
[`assert_matches`]: https://fuchsia-docs.firebaseapp.com/rust/assert_matches/index.html
[`pretty_assertions`]: https://fuchsia-docs.firebaseapp.com/rust/pretty_assertions/index.html