6个版本
| 0.3.1 | 2024年3月5日 |
|---|---|
| 0.3.0 | 2021年11月10日 |
| 0.2.1 | 2021年5月21日 |
| 0.2.0 | 2021年2月26日 |
| 0.1.0 | 2020年11月16日 |
#1498 在 过程宏 中
每月1,276次下载
在 8 个Crates中使用(通过 defmt-test)
28KB
461 行
defmt-test
defmt-test 是一个嵌入式设备的测试框架,允许您像使用内置的 #[test] 属性一样编写和运行单元测试。
它与 rust-analyzer 的 ▶ 运行测试 按钮兼容,这意味着您可以直接从VS Code闪烁和运行测试。

有关 defmt-test 的完整功能列表,请参阅下面的文档。
在新的项目中使用 defmt-test
我们建议您从 app-template 开始。从这里,您可以执行 cargo test --lib 来运行库单元测试,即库Crates(src/lib.rs)中的 #[test] 函数。
$ cargo test --lib
(..)
(1/1) running `it_works`...
└─ app::unit_tests::__defmt_test_entry @ src/lib.rs:33
all tests passed!
└─ app::unit_tests::__defmt_test_entry @ src/lib.rs:28
(..)
(HOST) INFO device halted without error
并执行 cargo test --test integration 来运行集成测试,即 tests/integration.rs 文件。
$ cargo test --test integration
(..)
0.000000 INFO (1/2) running `assert_true`...
└─ test::tests::__defmt_test_entry @ tests/test.rs:7
0.000001 INFO (2/2) running `assert_false`...
└─ test::tests::__defmt_test_entry @ tests/test.rs:7
0.000002 ERROR panicked at 'TODO: write actual tests', testsuite/tests/test.rs:16:9
└─ panic_probe::print_defmt::print @ (..omitted..)
stack backtrace:
0: HardFaultTrampoline
<exception entry>
1: __udf
2: cortex_m::asm::udf
at (..omitted..)
3: rust_begin_unwind
at (..omitted..)
4: core::panicking::panic_fmt
at (..omitted..)
5: core::panicking::panic
at (..omitted..)
6: test::tests::assert_false
at tests/test.rs:16
7: main
at tests/test.rs:7
8: ResetTrampoline
at (..omitted..)
9: Reset
at (..omitted..)
注意:文件中所有 #[test] 函数都将按顺序运行。
将 defmt-test 添加到现有项目中
如果您想将 defmt-test 添加到现有的 Cargo 项目/包中,对于您想要测试的每个 crate,您需要在 Cargo.toml 中进行以下更改
- 将
defmt-test添加为dev-dependency - 对于您想要测试的每个 crate,将
harness设置为false以禁用默认测试 harness,即依赖于std的testcrate。以下是一些示例
# Cargo.toml
# for the library crate (src/lib.rs)
[lib]
harness = false
# for each crate in the `tests` directory
[[test]]
name = "test-name" # tests/test-name.rs
harness = false
[[test]]
name = "second" # tests/second.rs
harness = false
需要注意的是,cargo test 会编译包或 workspace 中的 所有 crate。这可能包括您不想测试的 crate,例如 src/main.rs 或 src/bin 或 examples 中的每个 crate。要确定 cargo test 正在编译哪些 crate,请运行 cargo test -j1 -v 并查找每个 rustc 调用传递的 --crate-name 标志。
要仅测试包/工作空间中的一部分 crate,您有两个选择
- 您可以在调用
cargo test时指定每个 crate。例如,cargo test --lib --test integration测试了两个 crate:库 crate(《code>src/lib.rs)和tests/integration.rs - 您还可以禁用您不想测试的 crate 的测试 - 以下是一个示例 - 然后您可以使用
cargo test来测试所有未禁用的 crate。
如果您有这种项目结构
$ tree .
.
├── Cargo.toml
├── src
│ ├── lib.rs
│ └── main.rs
└── tests
└── integration.rs
并且已将 src/lib.rs 设置为测试,但不想测试 src/main.rs,您需要禁用 src/main.rs 的测试
# Cargo.toml
[package]
# ..
name = "app"
[[bin]] # <- add this section
name = "app" # src/main.rs
test = false
添加状态
可以在 #[tests] 模块中编写 #[init] 函数。此函数将在所有单元测试之前执行,其返回值(测试套件 状态)可以作为参数传递给单元测试。
// state shared across unit tests
struct MyState {
flag: bool,
}
#[defmt_test::tests]
mod tests {
#[init]
fn init() -> super::MyState {
// state initial value
super::MyState {
flag: true,
}
}
// This function is called before each test case.
// It accesses the state created in `init`,
// though like with `test`, state access is optional.
#[before_each]
fn before_each(state: &mut super::MyState) {
defmt::println!("State flag before is {}", state.flag);
}
// This function is called after each test
#[after_each]
fn after_each(state: &mut super::MyState) {
defmt::println!("State flag after is {}", state.flag);
}
// this unit test doesn't access the state
#[test]
fn assert_true() {
assert!(true);
}
// but this test does
#[test]
fn assert_flag(state: &mut super::MyState) {
assert!(state.flag)
state.flag = false;
}
}
$ cargo test -p testsuite
0.000000 (1/2) running `assert_true`...
└─ integration::tests::__defmt_test_entry @ tests/integration.rs:37
0.000001 State flag before is true
└─ integration::tests::before_each @ tests/integration.rs:26
0.000002 State flag after is true
└─ integration::tests::after_each @ tests/integration.rs:32
0.000003 (2/2) running `assert_flag`...
└─ integration::tests::__defmt_test_entry @ tests/integration.rs:43
0.000004 State flag before is true
└─ integration::tests::before_each @ tests/integration.rs:26
0.000005 State flag after is false
└─ integration::tests::after_each @ tests/integration.rs:32
0.000006 all tests passed!
└─ integration::tests::__defmt_test_entry @ tests/integration.rs:11
测试结果
测试函数可以返回 () 并在失败时 panic,或者返回任何实现了 TestOutcome 特性的类型,例如 Result。
这允许测试通过 Result 指示失败,这允许使用 ? 操作符来传播错误。
类似于 Rust 内置的 #[should_panic] 属性,defmt-test 支持一个 #[should_error] 属性,它反转了返回的 TestOutcome 的意义。 Err 使测试通过,而 Ok/() 则使测试失败。
支持
defmt-test 是 Knurling 项目的一部分,这是 Ferrous Systems 用来改进嵌入式系统开发工具的努力。
如果您认为我们的工作很有用,请考虑通过 GitHub Sponsors 进行赞助。
许可协议
许可协议为以下之一:
-
Apache License, Version 2.0 (LICENSE-APACHE 或 https://apache.ac.cn/licenses/LICENSE-2.0)
-
MIT 许可协议 (LICENSE-MIT 或 https://open-source.org.cn/licenses/MIT)
任选其一。
贡献
除非您明确声明,否则根据 Apache-2.0 许可证定义的,您有意提交的任何贡献,均应按照上述许可证进行许可,不附加任何额外条款或条件。
依赖关系
~295–750KB
~18K SLoC