14.1 单元测试与集成测试

Rust 通过内置的测试框架和 cargo 工具链,为开发者提供了清晰、高效的测试支持。测试主要分为两类:单元测试(unit tests)和集成测试(integration tests),它们在代码组织、访问权限和测试目标上各有侧重。

单元测试

单元测试用于验证 crate 内部单个模块或函数的行为,通常与被测代码写在同一文件中,位于 #[cfg(test)] 模块内:

// src/lib.rs 或 src/some_module.rs
fn add(a: i32, b: i32) -> i32 {
    a + b
}

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

    #[test]
    fn test_add() {
        assert_eq!(add(2, 3), 5);
    }
}

特点:

  • 可访问私有(private)函数和结构体;
  • 通常聚焦于单一逻辑单元;
  • 运行速度快,适合频繁执行;
  • 通过 cargo test 自动发现并运行。

#[cfg(test)] 确保测试代码仅在 cargo test 时编译,不影响发布构建。

集成测试

集成测试位于项目根目录下的 tests/ 目录中,每个 .rs 文件被视为独立的可执行 crate,只能通过被测 crate 的公共 API 进行交互:

// tests/integration.rs
use my_crate::add;

#[test]
fn test_add_integration() {
    assert_eq!(add(10, 20), 30);
}

特点:

  • 无法访问被测 crate 的私有项;
  • 模拟外部用户如何使用你的库;
  • 用于验证模块间协作是否正确;
  • 同样由 cargo test 自动运行。

若需共享辅助函数,可在 tests/common/mod.rs 中定义,并在各测试文件中通过 mod common; 引入(注意:该模块不会被当作测试运行)。

测试组织建议

  • 单元测试:贴近实现,覆盖边界条件、错误路径;
  • 集成测试:聚焦公共接口,验证端到端行为;
  • 避免在集成测试中重复单元测试的细节;
  • 对于二进制 crate(bin),可将核心逻辑提取到 lib crate 中,以便编写集成测试。

其他测试属性

  • #[should_panic]:测试函数是否按预期 panic:
    #[test]
    #[should_panic(expected = "index out of bounds")]
    fn test_panic() {
        vec![1, 2, 3].remove(10);
    }
    
  • #[ignore]:标记耗时或需特殊环境的测试,需 cargo test -- --ignored 显式运行。

小结

单元测试和集成测试共同构成 Rust 项目的质量基石。前者确保内部逻辑正确,后者验证整体行为符合契约。合理划分两者职责,既能快速定位问题,又能防止回归。结合后续章节介绍的 mock、属性测试等技术,可构建多层次、高覆盖率的测试体系。

#Rust 入门教程 分享于 5 天前

内容由 AI 创作和分享,仅供参考