1 个不稳定版本

0.0.1 2023 年 1 月 4 日

#5#llvm-mos

MIT/Apache

11KB
97

mos-test

mos-test 是将出色的 defmt-test 端口移植到 mos 架构。它是一个替代测试框架,允许您在所有 llvm-mos 平台上编写和运行单元测试,就像您正在使用内置的 #[test] 属性一样。

它与 rust-analyzer▶ 运行测试 按钮兼容,这意味着您可以直接从 VS Code 运行测试。

有关 mos-test 的全部功能,请参阅下面的文档。

mos-test 添加到现有项目

如果您想将 mos-test 添加到现有的 Cargo 项目 / 包,对于您想要测试的每个 crate,您需要在 Cargo.toml 中进行以下更改

  • mos-test 添加为 dev-dependency
  • 对于您想要测试的每个 crate,将 harness 设置为 false 以禁用默认测试框架,即依赖于 stdtest crate。以下示例
# Cargo.toml

# for the library crate (src/lib.rs)
[lib]
harness = false

# for the bin crate (src/main.rs)
[[bin]]
name = "binary_name"
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 将编译包或工作空间中的所有 crate,这可能包括您不想测试的 crate,如 src/main.rssrc/binexamples 中的每个 crate。要确定 cargo test 编译了哪些 crate,请运行 cargo test -j1 -v 并查找传递给每个 rustc 调用的 --crate-name 标志。

要仅测试包 / 工作空间中 crate 的一部分,您有两个选择

  • 当您调用 cargo test 命令时,可以指定每个 crate。例如,cargo test --lib --test integration 会测试两个 crate:库 crate(《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

测试结果

测试函数可以返回 () 并在失败时恐慌,或者返回任何实现了 TestOutcome 特性的其他类型,例如 Result

这允许测试通过 Result 表明失败,这允许使用 ? 操作符传播错误。

类似于 Rust 的内置 #[should_panic] 属性,mos-test 支持一个 #[should_error] 属性,它反转了返回的 TestOutcome 的意义。Err 使得测试通过,而 Ok/() 则使测试失败。

许可证

根据您的要求,许可为以下之一

贡献

除非您明确声明,否则根据 Apache-2.0 许可证定义,您有意提交以包含在作品中的任何贡献,将根据上述条款许可,而无需任何附加条款或条件。

依赖项

约 1.5MB
约 39K SLoC