Rust 中的测试函数是用来验证非测试代码是否按照期望的方式运行的。测试函数体通常执行如下三种操作:

  1. 设置任何所需的数据或状态
  2. 运行需要测试的代码
  3. 断言其结果是我们所期望的

    测试函数剖析

    Rust 测试是带有 test 属性注解的函数。
    新建 lib crate
    1. $ cargo new adder --lib
    2. Created library `adder` project
    3. $ cd adder
    测试
    1. #[cfg(test)]
    2. mod tests {
    3. #[test]
    4. fn it_works() {
    5. assert_eq!(2 + 2, 4);
    6. }
    7. }

    使用 assert! 宏来检查结果

    assert! 宏由标准库提供,对 boolean 条件的测试非常有用

    使用 assert_eq! 和 assert_ne! 宏来测试相等

    ```rust pub fn add_two(a: i32) -> i32 { a + 2 }

[cfg(test)]

mod tests { use super::*;

  1. #[test]
  2. fn it_adds_two() {
  3. assert_eq!(4, add_two(2));
  4. }

}

  1. 需要注意的是,在一些语言和测试框架中,断言两个值相等的函数的参数叫做 expected actual,而且指定参数的顺序是很关键的。然而在 Rust 中,他们则叫做 left right,同时**指定期望的值和被测试代码产生的值的顺序并不重要**。
  2. <a name="bkhE2"></a>
  3. ## 自定义失败信息
  4. 为测试函数增加一个自定义失败信息参数:带占位符的格式字符串,以及 greeting 函数的值:
  5. ```rust
  6. pub fn greeting(name: &str) -> String {
  7. String::from("Hello!")
  8. }
  9. #[cfg(test)]
  10. mod tests {
  11. use super::*;
  12. #[test]
  13. fn greeting_contains_name() {
  14. let result = greeting("Carol");
  15. assert!(
  16. result.contains("Carol"),
  17. "Greeting did not contain name, value was `{}`",
  18. result
  19. );
  20. }
  21. }
  1. $ cargo test
  2. Compiling greeter v0.1.0 (file:///projects/greeter)
  3. Finished test [unoptimized + debuginfo] target(s) in 0.93s
  4. Running unittests (target/debug/deps/greeter-170b942eb5bf5e3a)
  5. running 1 test
  6. test tests::greeting_contains_name ... FAILED
  7. failures:
  8. ---- tests::greeting_contains_name stdout ----
  9. thread 'main' panicked at 'Greeting did not contain name, value was `Hello!`', src/lib.rs:12:9
  10. note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
  11. failures:
  12. tests::greeting_contains_name
  13. test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
  14. error: test failed, to rerun pass '--lib'

使用 should_panic 检查 panic

  1. pub struct Guess {
  2. value: i32,
  3. }
  4. // --snip--
  5. impl Guess {
  6. pub fn new(value: i32) -> Guess {
  7. if value < 1 {
  8. panic!(
  9. "Guess value must be greater than or equal to 1, got {}.",
  10. value
  11. );
  12. } else if value > 100 {
  13. panic!(
  14. "Guess value must be less than or equal to 100, got {}.",
  15. value
  16. );
  17. }
  18. Guess { value }
  19. }
  20. }
  21. #[cfg(test)]
  22. mod tests {
  23. use super::*;
  24. #[test]
  25. #[should_panic(expected = "Guess value must be less than or equal to 100")]
  26. fn greater_than_100() {
  27. Guess::new(200);
  28. }
  29. }

将 Result 用于测试

  1. #[cfg(test)]
  2. mod tests {
  3. #[test]
  4. fn it_works() -> Result<(), String> {
  5. if 2 + 2 == 4 {
  6. Ok(())
  7. } else {
  8. Err(String::from("two plus two does not equal four"))
  9. }
  10. }
  11. }

为了断言一个操作返回 Err 成员,不要使用对 Result 值使用问号表达式(?)。而是使用 assert!(value.is_err())