1.6 测试

原文链接: https://rust-unofficial.github.io/too-many-lists/first-test.html

好了,push 和 pop 都写好了,现在可以真正测试我们的栈了!Rust 和 cargo 把测试当作一等公民,所以这会超级简单。我们只需写一个函数,并用 #[test] 标注。

在 Rust 社区里,我们通常把测试放在被测代码旁边。不过一般会为测试新建一个命名空间,避免与「真实」代码冲突。就像我们用 mod 指定 first.rs 应包含在 lib.rs 里一样,也可以用 mod 基本上内联创建一个全新文件:

1
2
3
4
5
6
7
8
// 在 first.rs 中

mod test {
    #[test]
    fn basics() {
        // TODO
    }
}

用 cargo test 运行。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
> cargo test
   Compiling lists v0.1.0 (/Users/ADesires/dev/temp/lists)
    Finished dev [unoptimized + debuginfo] target(s) in 1.00s
     Running /Users/ADesires/dev/lists/target/debug/deps/lists-86544f1d97438f1f

running 1 test
test first::test::basics ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
; 0 filtered out

耶,啥也不干的测试通过了!让它干点事。用 assert_eq! 宏。这不是什么特殊的测试魔法。它只是比较你给它的两个东西,不匹配就让程序 panic。没错,向测试框架表示失败的方式就是抓狂!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
mod test {
    #[test]
    fn basics() {
        let mut list = List::new();

        // 检查空链表行为正确
        assert_eq!(list.pop(), None);

        // 填充链表
        list.push(1);
        list.push(2);
        list.push(3);

        // 检查正常弹出
        assert_eq!(list.pop(), Some(3));
        assert_eq!(list.pop(), Some(2));

        // 再推入一些,确保没有损坏
        list.push(4);
        list.push(5);

        // 检查正常弹出
        assert_eq!(list.pop(), Some(5));
        assert_eq!(list.pop(), Some(4));

        // 检查耗尽
        assert_eq!(list.pop(), Some(1));
        assert_eq!(list.pop(), None);
    }
}
1
2
3
4
5
6
7
> cargo test

error[E0433]: failed to resolve: use of undeclared type or module `List`
  --> src/first.rs:43:24
   |
43 |         let mut list = List::new();
   |                        ^^^^ use of undeclared type or module `List`

哎呀!因为我们新建了模块,需要显式引入 List 才能用。

1
2
3
4
mod test {
    use super::List;
    // 其余相同
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
> cargo test

warning: unused import: `super::List`
  --> src/first.rs:45:9
   |
45 |     use super::List;
   |         ^^^^^^^^^^^
   |
   = note: #[warn(unused_imports)] on by default

    Finished dev [unoptimized + debuginfo] target(s) in 0.43s
     Running /Users/ADesires/dev/lists/target/debug/deps/lists-86544f1d97438f1f

running 1 test
test first::test::basics ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
; 0 filtered out

耶!

那个警告怎么回事……?我们明明在测试里用了 List!

……但只在测试时!为了安抚编译器(也对使用者友好),应标明整个 test 模块只在运行测试时编译。

1
2
3
4
5
#[cfg(test)]
mod test {
    use super::List;
    // 其余相同
}

测试部分就这些了!

最后修改 August 23, 2026: 更新 (499855b16)