» Rust快速入门 » 2. 高级篇 » 2.7 测试

测试

Rust 语言原生支持写测试。

单元测试

测试是验证业务代码是否按预期运行的函数。大多数单元测试都在 tests 模块中使用 #[cfg(test)] 属性标记,其测试函数使用 #[test] 属性标记。

// 导入要测试的模块
use crate::my_module;

#[cfg(test)]
mod tests {
    // 导入测试所需的项
    use super::*;

    // add 函数的单元测试
    #[test]
    fn test_add() {
        let a = 3;
        let b = 4;

        let result = my_module::add(a, b);

        // 断言:检查结果
        assert_eq!(result, 7);
    }

    // 更多测试
}

使用 cargo test 命令可以运行测试。

$ cargo test

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

测试 panic

为了检查在特定情况下应该引发 panic 的函数,使用属性 #[should_panic]

pub fn divide(a: i32, b: i32) -> i32 {
    if b == 0 {
        panic!("Cannot divide by zero!");
    }
    a / b
}

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

    // 使用 should_panic 检查 panic
    #[test]
    #[should_panic]
    fn test_divide_by_zero() {
        // 此调用预计引发 panic
        divide(10, 0);
    }
}

运行特定测试

要运行特定测试,可以给 cargo test 命令指定测试名称。

$ cargo test test_divide_by_zero

可以使用 #[ignore] 属性标记排除某些测试。

#[test]
#[ignore]
fn ignored_test() {
    assert_eq!(divide(58, 2), 29);
}

文档测试

Rust 项目的文档主要是通过对源代码进行文档注释生成。

/// 将两个数字相加并返回结果。
///
/// # Examples
///
/// `` `
/// let result = my_module::add(3, 4);
/// assert_eq!(result, 7);
/// `` `
pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

文档中的代码块在运行常规的 cargo test 命令时会自动进行测试。 或者,可以使用 cargo test --doc 命令专门运行文档测试。

集成测试

单元测试一次测试一个模块:它们很小并且可以测试私有代码。 集成测试是在 crate 外部的测试,并且仅使用其公共接口,就像其他正常调用代码一样。

你可以创建一个名为 tests/integration_test.rs 的集成测试文件,然后运行 cargo test 命令。

$ cargo test
   Compiling my_project v0.1.0 (/path/to/my_project)
    Finished test [unoptimized + debuginfo] target(s) in 0.71s
     Running target/debug/deps/my_project-<hash>

running 2 tests
test unit_test ... ok
test doc_test_placeholder ... ok
test integration_test ... ok

test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Dev Dependencies (开发依赖项)

有时需要为开发添加仅用于开发阶段的依赖项。 这些依赖项添加到 Cargo.toml 中的 [dev-dependencies] 部分。

[dev-dependencies]
pretty_assertions = "1"

然后在测试代码中可以这样做:

#[cfg(test)]
mod tests {
    // 从 pretty_assertions 导入宏
    use pretty_assertions::{assert_eq, assert_ne};

    #[test]
    fn test_example() {
        let expected = vec![1, 2, 3];
        let actual = vec![1, 2, 4];

        assert_eq!(expected, actual);

        assert_ne!(expected, vec![7, 8, 9]);
    }
}