Rust and defmt-test
Run embedded Rust tests through Cargo and rust-analyzer on OnMCU hardware.
You can use OnMCU as the Cargo runner for defmt-test. Add --ignore-trailing-args so Cargo and rust-analyzer can append their test arguments.
Configure the Cargo runner
Add the target and runner to the project's Cargo configuration:
[build]
target = "thumbv7em-none-eabihf"
[target.thumbv7em-none-eabihf]
runner = [
"onmcu",
"run",
"--board",
"NUCLEO-H743ZI",
"--ignore-trailing-args",
"--file",
]
rustflags = [
"-C", "link-arg=--nmagic",
"-C", "link-arg=-Tlink.x",
"-C", "link-arg=-Tdefmt.x",
]
[env]
DEFMT_LOG = "info"The argument order matters. Cargo appends the linked test ELF, then its filters and harness flags. The command above becomes:
onmcu run \
--board NUCLEO-H743ZI \
--ignore-trailing-args \
--file target/thumbv7em-none-eabihf/debug/deps/integration-… \
integration::tests::passes --exact --nocapture--file consumes the ELF path. --ignore-trailing-args discards the remaining development-tool arguments.
The filter is ignored on the device
OnMCU currently ignores the appended test name and harness arguments, so the selected defmt-test binary runs its full embedded suite. The VS Code button still builds and launches the right test target, but it may run every test in that target rather than only the function under the button. If you would like OnMCU to support per-test filtering, please reach out and let us know.
Add defmt-test
For an integration-test target:
[dev-dependencies]
defmt = "1"
defmt-rtt = "1"
defmt-test = "0.5"
panic-probe = { version = "1", features = ["print-defmt"] }
[[test]]
name = "integration"
harness = falseChoose the logger, panic handler, HAL, and chip features for your target. A minimal test file looks like this:
#![no_std]
#![no_main]
use defmt_rtt as _;
use panic_probe as _;
#[defmt_test::tests]
mod tests {
#[test]
fn arithmetic_works() {
defmt::assert_eq!(2 + 2, 4);
}
}Run it from a terminal:
cargo test --test integrationdefmt-test uses semihosting to halt the device after the suite. OnMCU reads that exit, stops the run, and returns the result without waiting for a timeout.
Run from rust-analyzer in VS Code
- Open the crate as the VS Code workspace so rust-analyzer loads its
.cargo/config.toml. - Confirm
onmcuis on the environmentPATHvisible to VS Code. - Authenticate with
onmcu login. - Open the test file and select Run Test above the
#[test]function or#[defmt_test::tests]module.
rust-analyzer calls Cargo, which builds the test ELF and starts OnMCU. The output appears in VS Code's Rust test terminal.
If VS Code was already running when you installed the CLI, restart it so the extension receives the updated PATH.
CI authentication
Do not use the keyring in CI. Extend the runner with --api-key-from-env, then provide ONMCU_API_KEY through the job's secret environment:
[target.thumbv7em-none-eabihf]
runner = [
"onmcu",
"run",
"--board",
"NUCLEO-H743ZI",
"--api-key-from-env",
"--ignore-trailing-args",
"--file",
]- name: Run embedded tests
env:
ONMCU_API_KEY: ${{ secrets.ONMCU_API_KEY }}
run: cargo test --test integrationIf you build the ELF in a separate GitHub Actions step, use the OnMCU Action. Keep the Cargo runner when you want to use the same cargo test command locally and in CI.
Why the flag is opt-in
Without --ignore-trailing-args, unexpected values produce a usage error with exit code 2. This catches misspelled CLI options. Enable the flag only in runner configurations where Cargo or an editor is expected to append test arguments.