Skip to content
Published at:

编写自动化测试

如何编写测试

Hello world

rust
#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }
}

运行:

bash
$ cargo test

断言宏

  • assert!: 真假
  • assert_eq!:是否相同
  • assert_ne!:是否不相同

如果失败,内部会调用panic!;assert会在debug和release版本中都生效,debug_assert默认只在非优化构建(非release)的版本中生效

  • debug_assert!: 真假
  • debug_assert_eq!:是否相同
  • debug_assert_ne!:是否不相同

自定义message

assert后面的参数, 请看std::fmt

rust
#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        // assert with a custom message
        let x = true;
        assert!(x, "x wasn't true!");

        let a = 3;
        let b = 27;
        assert!(a + b == 301, "a = {}, b = {}", a, b);
    }
}

should_panic检查panic

如果程序执行到了panic,表示测试通过

rust
pub struct Guess {
    value: i32,
}
impl Guess {
    pub fn new(value: i32) -> Guess {
        if value < 1 || value > 100 {
            panic!("Guess value must be between 1 and 100, got {}.", value);
        }
        Guess { value }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    #[should_panic]  // should_panic注解
    fn greater_than_100() {
        Guess::new(200);
    }
}

Result<T, E>用于测试

Err可以携带错误信息,在测试失败时,会打印出来

rust
#[cfg(test)]
mod tests {
    #[test]
    fn it_works() -> Result<(), String> {
        if 2 + 2 == 4 {
            Ok(())
        } else {
            Err(String::from("two plus two does not equal four"))
        }
    }
}

使用Result同时不能使用should_panic

控制测试运行

bash
# -- 后面的是参数是:传递给二进制的参数
$ cargo test -- --help

# 当运行多个测试时,Rust默认使用线程来并行运行;设置线程数
$ cargo test -- --test-threads=1

# Rust测试库会截获到标准输出的内容;如果测试成功了,就看不到println输出的内容,如果测试失败了,就可以看到相应的println输出内容
# 禁用rust的捕获输出内容,全部的标准输出会打印输出,和测试的成功失败无关
$ cargo test -- --nocapture

# 可以指定运行特定的测试,也可以是匹配(规则:是否包含)
$ cargo test one_hundred
$ cargo test add

# 排除执行使用了#[ignored]注解的测试
$ cargo test -- --ignored

测试的组织结构

单元测试与集成测试

  • 单元测试:内部测试一个模块,测试一个私有接口。(对内)
  • 集成测试:库对外的接口,别人集成你这个库调用的接口。(对外)

单元测试

#[cfg(test)]中cfg的意思是,告诉cargo test时会去编译和运行这部分代码;而cargo build不会去编译这部分代码,也不会打包到二进程程序中

rust
pub fn add_two(a: i32) -> i32 {
    internal_adder(a, 2)
}

fn internal_adder(a: i32, b: i32) -> i32 {
    a + b
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn internal() {
        assert_eq!(4, internal_adder(2, 2));
    }
}

集成测试

tests目录,和src同级

bash
adder
├── Cargo.lock
├── Cargo.toml
├── src
│   └── lib.rs
└── tests
    └── integration_test.rs

文件名: tests/integration_test.rs

rust
use adder;

#[test]
fn it_adds_two() {
    assert_eq!(4, adder::add_two(2));
}

运行:

bash
# 运行所有的测试
$ cargo test

# 运行指定的集成测试
$ cargo test --test integration_test