这次要来谈的是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:
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);
}
}
mod rv_core
,宣告rv_core模组依照Rust官方的教学,unit tests一般放在src/底下,目前直接与待测程序码放在同档案,以方便test code存取待测物。教学也有提到可以在src/旁边新增一个tests/资料夹来放test code,不过那是属於integration test的范畴,之後有需要再来研究。
完整的repo可以参考此连结
定义 访问一个物件上的属性时, 如果物件没有该属性, 就会执行委派, 让引擎顺着原型链向上查找, 并...
848. Shifting Letters https://leetcode.com/problem...
上午: 网站设计与网页工程技术 # 连接资料库 import sqlite3 import nump...
撰写大家熟知的终极密码 示意图 开始撰写 # cogs/guess.py @commands.com...
聊天机器人虽有问答集可以回覆大部分常见问题,但难免会有疏漏。因此本研究亦设计回馈机制,若使用者发现机...