#嵌入式设备 #测试执行器 #测试框架 #测试平台 #测试

无 std embedded-test

嵌入式设备测试平台和执行器

6 个版本

0.4.0 2024年5月31日
0.3.0 2024年2月5日
0.2.3 2024年1月26日
0.2.2 2023年12月27日
0.1.0 2023年12月6日

嵌入式开发 中排名第 150

Download history 4/week @ 2024-05-10 21/week @ 2024-05-17 6/week @ 2024-05-24 286/week @ 2024-05-31 186/week @ 2024-06-07 613/week @ 2024-06-14 840/week @ 2024-06-21 1204/week @ 2024-06-28 1068/week @ 2024-07-05 1889/week @ 2024-07-12 2214/week @ 2024-07-19 2272/week @ 2024-07-26 2385/week @ 2024-08-02 3922/week @ 2024-08-09 2013/week @ 2024-08-16

每月下载量 11,051
用于 sam3-hal

MIT/Apache

3.5MB
319 行代码(不含注释)

嵌入式测试

Crates.io Crates.io

嵌入式-test 库为嵌入式系统(riscv、arm 和 xtensa)提供测试平台。在目标设备上使用此库,与主机上的 probe-rs 一起运行集成测试。

probe-rs 与嵌入式-test 一起提供(与 libtest 兼容的)测试执行器,它将

  1. 一次性将所有测试闪存到设备中(通过 probe-rs run 命令)
  2. 从设备请求有关所有测试的信息(通过半主机 SYS_GET_CMDLINE)
  3. 依次对每个测试用例
    • 重置设备
    • 向设备发送信号(通过半主机 SYS_GET_CMDLINE)以运行哪个测试
    • 等待设备发送测试完成成功或出错(通过半主机 SYS_EXIT)的信号
  4. 报告结果

由于测试执行器(probe-rs run)与 libtest 兼容(使用 libtest-mimic),您可以使用 intellij 或 vscode 通过单击按钮运行单个测试。

功能

  • 独立运行每个测试用例,并在每个测试用例之间重置设备
  • 支持初始化函数,该函数将在每个测试用例之前调用,并可以将状态传递给测试用例
  • 支持异步测试和初始化函数(需要功能 embassy
  • 支持为每个测试用例提供 #[should_panic]#[ignore]#[timeout(<seconds>)] 属性

用法

将以下内容添加到您的 Cargo.toml

[dev-dependencies]
embedded-test = { version = "0.4.0", features = ["init-log"] }


[[test]]
name = "example_test"
harness = false

在您的系统上安装runner

cargo install probe-rs-tools

将以下内容添加到您的 .cargo/config.toml

[target.riscv32imac-unknown-none-elf]
runner = "probe-rs run --chip esp32c6"
# `probe-rs run` will autodetect whether the elf to flash is a normal firmware or a test binary

将以下内容添加到您的 build.rs 文件中

fn main() {
    println!("cargo::rustc-link-arg-tests=-Tembedded-test.x");
}

然后您可以使用 cargo test --test example_test 运行您的测试,或者在vscode/intellij中使用按钮。

设置时遇到问题?请查看 常见问题解答和错误 Wiki页面。

示例测试

示例仓库
更详细的Cargo.toml
异步测试示例

tests/example_test.rs 示例

#![no_std]
#![no_main]

#[cfg(test)]
#[embedded_test::tests]
mod tests {
    use esp_hal::{clock::ClockControl, delay::Delay, peripherals::Peripherals, prelude::*};

    // Optional: A init function which is called before every test
    #[init]
    fn init() -> Delay {
        let peripherals = Peripherals::take();
        let system = peripherals.SYSTEM.split();
        let clocks = ClockControl::max(system.clock_control).freeze();
        let delay = Delay::new(&clocks);

        // The init function can return some state, which can be consumed by the testcases
        delay
    }

    // A test which takes the state returned by the init function (optional)
    #[test]
    fn takes_state(_state: Delay) {
        assert!(true)
    }

    // Example for a test which is conditionally enabled
    #[test]
    #[cfg(feature = "log")]
    fn log() {
        log::info!("Hello, log!"); // Prints via esp-println to rtt
        assert!(true)
    }

    // Another example for a conditionally enabled test
    #[test]
    #[cfg(feature = "defmt")]
    fn defmt() {
        use defmt_rtt as _;
        defmt::info!("Hello, defmt!"); // Prints via defmt-rtt to rtt
        assert!(true)
    }

    // A test which is cfg'ed out
    #[test]
    #[cfg(abc)]
    fn it_works_disabled() {
        assert!(false)
    }

    // Tests can be ignored with the #[ignore] attribute
    #[test]
    #[ignore]
    fn it_works_ignored() {
        assert!(false)
    }

    // A test that fails with a panic
    #[test]
    fn it_fails1() {
        assert!(false)
    }

    // A test that fails with a returned Err(&str)
    #[test]
    fn it_fails2() -> Result<(), &'static str> {
        Err("It failed because ...")
    }

    // Tests can be annotated with #[should_panic] if they are expected to panic
    #[test]
    #[should_panic]
    fn it_passes() {
        assert!(false)
    }

    // This test should panic, but doesn't => it fails
    #[test]
    #[should_panic]
    fn it_fails3() {}

    // Tests can be annotated with #[timeout(<secs>)] to change the default timeout of 60s
    #[test]
    #[timeout(10)]
    fn it_timeouts() {
        loop {} // should run into the 10s timeout
    }
}

配置特性

特性 默认值? 描述
panic-handler 定义一个panic处理器,当发生panic时会调用 semihosting::process::abort()
defmt 将测试用例退出结果打印到defmt。您需要自己设置defmt #[global_logger]
log 将测试用例退出结果打印到日志。您需要自己设置日志接收器(或与init-log特性结合使用)。
init-rtt 在开始任何测试之前调用 rtt_target::rtt_init_print!()
init-log 在开始任何测试之前调用 rtt_log::init();
embassy 启用异步测试和初始化函数。注意:除非您使用external-executor特性,否则您需要在embassy-executor crate上启用至少一个executor特性。
external-executor 允许您使用自己的embassy executor,您需要将其传递给#[tests]宏(例如#[embedded_test::tests(executor = esp_hal::embassy::executor::thread::Executor::new())])
xtensa-semihosting 为xtensa目标启用半主机。

许可证

根据您的选择,许可如下

贡献

除非您明确表示,否则您提交的任何贡献,根据Apache-2.0许可证定义,都应按照上述方式双重许可,没有任何附加条款或条件。

依赖项