RISC-V on Rust 从零开始(4) - Rust 测试工具

这次要来谈的是Rust的测试框架,并且重新调整目录架构。

撰写测试

Rust本身就自带测试框架,无须安装额外library,这边直接把上次所写的main改写成test case如下:

fn main() {
    let mut core: RVCore = Default::default();
    core.run(5);
}

#[test]
fn test_core_run() {
    // Copy from main
    let mut core: RVCore = Default::default();
    core.run(5);
}

可以看到在定义fn的前面多了一个#[test] 属性,代表这是一个test case 的定义,凡是带有test属性的function就会自动被当作测试执行。

cargo test 就可以看到测试结果:

#[test]
running 1 test
test test_core_run ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

只是把core跑起来没有用处,测试需要断言(assertion)来判断程序的正确性:

#[test]
fn test_core_run() {
    let mut core: RVCore = Default::default();
    assert_eq!(0, core.pc);

    core.run(5);
    assert_eq!(20, core.pc);
}

assert_eq是Rust内建的macro,很多测试框架的convention都是把预期值放左边,实际值放右边,这里也遵循此规则。初始化之後我们预期core的PC应该为0,跑了5个指令後,假设每个指令长度为4,PC就会变成5*4 = 20。重新执行cargo test,一样可以看到test pass的输出。

为了观察test fail会发生什麽事,先把最後一行改成如下:

assert_eq!(10, core.pc);

执行cargo test就会看到test fail的讯息,以及是哪个test case 的哪一行fail:

thread 'test_core_run' panicked at 'assertion failed: `(left == right)`
  left: `10`,
 right: `20`', src/main.rs:33:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

在test case数量很多时,这些都是很有用的资讯,可以帮助我们快速定位出错的地方。

调整目录结构

到目前为止所有程序码都写在同一个档案,虽然易於管理,当程序码逐渐增加,可读性很容易随之降低。这边将RVCore的实作独立成为module:

  • 建立src/rv_core.rs,将RVCore的定义以及test code全部搬过去
  • 修改RVCore可见度,所有会被外部使用的成员都要加上pub修饰词,目前有2个地方需要修改
    • pub struct RVCore // RVCore需要被外部的main.rs使用,必须为public
    • pub fn run() // main.rs会呼叫此method
  • 修改test code,用tests module包起来并且加上cfg(test)属性,以避免cargo run编译test code,以加速编译。修改结果如下:
#[cfg(test)]
mod tests {
    use super::*; // 使RVCore所有成员在此module中可见

    #[test]
    fn test_core_run() {
        let mut core: RVCore = Default::default();
        assert_eq!(0, core.pc);

        core.run(5);
        assert_eq!(20, core.pc);
    }
}
  • 修改main.rs,加上适当的prefix
    • 在一开始加上mod rv_core,宣告rv_core模组
    • 所有的RVCore都要改成rv_core::RVCore,代表我想使用的是rv_core模组里面的RVCore

依照Rust官方的教学,unit tests一般放在src/底下,目前直接与待测程序码放在同档案,以方便test code存取待测物。教学也有提到可以在src/旁边新增一个tests/资料夹来放test code,不过那是属於integration test的范畴,之後有需要再来研究。

完整的repo可以参考此连结


<<:  Day 32 (Jq-UI)

>>:  狗狗币的技术与理想的深入解析

Day01【JS】Behavior Delegation 行为委派

定义 访问一个物件上的属性时, 如果物件没有该属性, 就会执行委派, 让引擎顺着原型链向上查找, 并...

LeetCode解题 Day08

848. Shifting Letters https://leetcode.com/problem...

Day36 参加职训(机器学习与资料分析工程师培训班),网站设计与网页工程技术

上午: 网站设计与网页工程技术 # 连接资料库 import sqlite3 import nump...

终极密码DC版

撰写大家熟知的终极密码 示意图 开始撰写 # cogs/guess.py @commands.com...

Day 21 - [语料库模型] 09-回馈机制

聊天机器人虽有问答集可以回覆大部分常见问题,但难免会有疏漏。因此本研究亦设计回馈机制,若使用者发现机...