blob: f1daaf6fd384c7a631e7459501a47e4075856130 [file] [log] [blame] [view]
# Testing Rust code
This document describes best practices for writing tests for Rust code, and
paired with ["Running tests as components"][component_tests] describes how to
component-ize, package, and run these tests.
This document is targeted towards developers working inside of `fuchsia.git`,
and the workflow described is unlikely to work for SDK 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 `#[test]` will
be run as a test, and if the function successfully returns then the test passes.
For tests exercising asynchronous code, use the
`#[fasync::run_until_stalled(test)]` annotation as an alternative to
using an asynchronous executor.
```rust
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/hello_world/rust/src/main.rs" region_tag="async_test" adjust_indentation="auto" %}
```
### 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, they will need to be
packaged first. This is currently a two step process, which includes writing
a package manifest and the package build target.
#### Writing the package manifest
A package manifest is currently required. The manifest is placed in the
`meta/` subdirectory, immediately below the directory containing your `BUILD.gn`
file.
A minimal manifest file is shown below, and **must** be named the same as the
`name` attribute of the target that is being generated by the `rustc_binary` or
`rustc_library` above.
In case of a manifest for a `rustc_binary` given above, the resulting manifest
is:
```cmx
{
"program": {
"binary": "test/hello_world_rust_bin_test"
}
}
```
Note:
* The binary name is based on the `name = "hello_world_rust"` line on the
`rustc_binary` target.
* The binary is inside a `test/` subdirectory. This placement is implicit in the
`rustc_binary` build rule.
* You may have noticed that the package manifests are somewhat formulaic.
In the future, we may find ourselves able to automatically generate the
package manifests instead of having to write them out by hand.
In case of a manifest for a `rustc_library`, the manifest and the naming scheme
are similar. But pay attention to the subtle naming difference in the value
for the stanza `program.binary`:
```cmx
{
"program": {
"binary": "test/hello_world_rust_lib_test"
}
}
```
The `_lib_test` suffix is hard-coded in the `rustc_library` build rule, and
`hello_world_rust` again comes from the `name` attribute in the build rule.
#### Writing the package build target
For the Hello world binary example, the test package needs to reference 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).
If you are building a library instead,
then the library name will be `hello_world_rust_lib_test`.
```gn
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/hello_world/rust/BUILD.gn" indented_block="^test_package\(\"hello_world_rust_tests\"\) {" %}
```
To run the tests run:
```sh
fx test hello_world_rust_tests
```
Note: that in order to use `fx test`, you can't override
`package_name="..."` in your `package` or `test_package` declaration. This
issue is tracked by BLD-338.
For information on packaging and running tests, please refer to the
[documentation on running tests as components][component_tests].
[component_tests]:/docs/development/testing/running_tests_as_components.md
[example-src]: /examples/hello_world/rust