测试

我们现在已经实现了pushpop,就可以测试我们的栈了!Rust和cargo把测试作为一个一级特性来实现,所以写起测试来会很轻松。我们需要做的只是写一个函数,然后用#[test]标记它。

通常在Rust社区中,我们会把测试代码放在它所测试的部分的附近。不过我们通常会为测试创建单独的命名空间,来让它不与“真正的”代码产生冲突。就像我们用mod来表明first.rs应该被包含在lib.rs中,可以使用mod内联的创建一个新文件:

  1. // in first.rs
  2. mod test {
  3. #[test]
  4. fn basics() {
  5. // TODO
  6. }
  7. }

之后,我们通过cargo test调用它。

  1. > cargo test
  2. Compiling lists v0.1.0 (file:///Users/ABeingessner/dev/too-many-lists/lists)
  3. Running target/debug/lists-5c71138492ad4b4a
  4. running 1 test
  5. test first::test::basics ... ok
  6. test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
  7. Doc-tests lists
  8. running 0 tests
  9. test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured

好的,我们的什么都不做的测试通过了!我们来让它实际做些事吧。我们会使用assert_eq!宏来进行测试。这不是什么特殊的测试魔法。它所做的仅仅是比较你给它的两个值,并且让在它们不相等的情况下让程序panic。没错,你通过崩溃来指出测试中的失败!

  1. mod test {
  2. #[test]
  3. fn basics() {
  4. let mut list = List::new();
  5. // 检查空列表行为正确
  6. assert_eq!(list.pop(), None);
  7. // 填充列表
  8. list.push(1);
  9. list.push(2);
  10. list.push(3);
  11. // 检查通常的移除
  12. assert_eq!(list.pop(), Some(3));
  13. assert_eq!(list.pop(), Some(2));
  14. // 推入更多元素来确认没有问题
  15. list.push(4);
  16. list.push(5);
  17. // 检查通常的移除
  18. assert_eq!(list.pop(), Some(5));
  19. assert_eq!(list.pop(), Some(4));
  20. // 检查完全移除
  21. assert_eq!(list.pop(), Some(1));
  22. assert_eq!(list.pop(), None);
  23. }
  24. }
  1. > cargo test
  2. Compiling lists v0.1.0 (file:///Users/ABeingessner/dev/too-many-lists/lists)
  3. src/first.rs:47:24: 47:33 error: failed to resolve. Use of undeclared type or module `List` [E0433]
  4. src/first.rs:47 let mut list = List::new();
  5. ^~~~~~~~~
  6. src/first.rs:47:24: 47:33 error: unresolved name `List::new` [E0425]
  7. src/first.rs:47 let mut list = List::new();
  8. ^~~~~~~~~
  9. error: aborting due to 2 previous errors

噢!因为我们做了一个新的模块,所以需要把List显式的导入进来才能使用它。

  1. mod test {
  2. use super::List;
  3. // 其他不变
  4. }
  1. > cargo test
  2. Compiling lists v0.1.0 (file:///Users/ABeingessner/dev/too-many-lists/lists)
  3. src/first.rs:45:9: 45:20 warning: unused import, #[warn(unused_imports)] on by default
  4. src/first.rs:45 use super::List;
  5. ^~~~~~~~~~~
  6. Running target/debug/lists-5c71138492ad4b4a
  7. running 1 test
  8. test first::test::basics ... ok
  9. test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
  10. Doc-tests lists
  11. running 0 tests
  12. test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured

好极了!

那个警告又是怎么回事呢……?我们清楚的在测试里用了List!

……但仅仅在测试的过程中!为了平息编译器(以及对库的使用者友好),我们应该指明test模块只会在运行测试的过程中编译。

  1. #[cfg(test)]
  2. mod test {
  3. use super::List;
  4. // everything else the same
  5. }

这就是关于测试的所有要点了!