09-Rust 测试与质量保证(单元测试 + 集成测试 + Mock + Benchmark + Fuzzing + CI/CD)

摘要:本文系统讲解 Rust 测试与质量保证体系,涵盖单元测试与集成测试、文档测试、Mock 与测试桩、性能测试(Benchmark)、模糊测试(Fuzzing)、CI/CD 集成等核心内容。每个知识点配有完整代码示例、对比表格、实战场景及常见问题解答,帮助开发者编写健壮的 Rust 代码。

关键词:Rust、测试、单元测试、集成测试、Mock、Benchmark、Fuzzing、CI/CD、质量保证

适合人群:已掌握 Rust 基础的开发者、想提高代码质量的程序员、想建立测试体系的团队

阅读时间:约 50 分钟

版本信息:Rust 1.70+ | 兼容 Windows/macOS/Linux


文章目录

  • 一、单元测试与集成测试
    • [1.1 单元测试](#1.1 单元测试)
    • [1.2 断言宏](#1.2 断言宏)
    • [1.3 集成测试](#1.3 集成测试)
    • [1.4 测试组织](#1.4 测试组织)
  • 二、文档测试
    • [2.1 文档测试基础](#2.1 文档测试基础)
    • [2.2 文档测试技巧](#2.2 文档测试技巧)
  • [三、Mock 与测试桩](#三、Mock 与测试桩)
    • [3.1 使用 mockall](#3.1 使用 mockall)
    • [3.2 测试桩模式](#3.2 测试桩模式)
  • [四、性能测试 Benchmark](#四、性能测试 Benchmark)
    • [4.1 使用 criterion](#4.1 使用 criterion)
    • [4.2 Benchmark 对比](#4.2 Benchmark 对比)
  • [五、模糊测试 Fuzzing](#五、模糊测试 Fuzzing)
    • [5.1 使用 cargo-fuzz](#5.1 使用 cargo-fuzz)
    • [5.2 Fuzzing 适用场景](#5.2 Fuzzing 适用场景)
  • [六、CI/CD 集成](#六、CI/CD 集成)
    • [6.1 GitHub Actions](#6.1 GitHub Actions)
    • [6.2 CI 检查项](#6.2 CI 检查项)
    • [6.3 测试覆盖率](#6.3 测试覆盖率)
  • [💡 综合实战案例](#💡 综合实战案例)
  • [❓ 常见问题 FAQ](#❓ 常见问题 FAQ)
  • [📝 学习资源与建议](#📝 学习资源与建议)
  • [📚 参考资料](#📚 参考资料)

一、单元测试与集成测试

1.1 单元测试

  Rust 内置测试框架,使用 #[test] 属性标记测试函数。

rust 复制代码
// src/lib.rs
pub 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);
    }

    #[test]
    fn test_add_negative() {
        assert_eq!(add(-1, 1), 0);
    }
}

测试运行命令

bash 复制代码
cargo test              # 运行所有测试
cargo test test_add     # 运行指定测试
cargo test -- --nocapture  # 显示输出

1.2 断言宏

断言宏对比

说明 示例
assert! 条件为真 assert!(x > 0)
assert_eq! 相等 assert_eq!(a, b)
assert_ne! 不相等 assert_ne!(a, b)
panic! 故意 panic panic!("expected error")

1.3 集成测试

  集成测试放在 tests/ 目录下,测试公共 API。

rust 复制代码
// tests/integration_test.rs
use my_crate::add;

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

测试类型对比

类型 位置 测试范围 访问权限
单元测试 src/ 内部实现 可访问私有项
集成测试 tests/ 目录 公共 API 仅公共项
文档测试 文档注释中 示例代码 公共项

1.4 测试组织

rust 复制代码
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_works() {
        let result = 2 + 2;
        assert_eq!(result, 4);
    }

    #[test]
    #[should_panic]
    fn it_panics() {
        panic!("This should panic");
    }

    #[test]
    #[ignore]
    fn expensive_test() {
        // 耗时测试,默认跳过
    }
}

测试属性对比

属性 说明 示例
#[test] 标记测试函数 #[test]
#[should_panic] 期望 panic #[should_panic]
#[ignore] 跳过测试 #[ignore]
#[serial] 串行执行 #[serial]

二、文档测试

2.1 文档测试基础

  Rust 允许在文档注释中编写可测试的代码示例。

rust 复制代码
/// Adds two numbers.
///
/// # Examples
///
/// ```
/// use my_crate::add;
///
/// assert_eq!(add(2, 3), 5);
/// ```
pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

文档测试运行

bash 复制代码
cargo test --doc    # 仅运行文档测试
cargo test          # 包含文档测试

2.2 文档测试技巧

rust 复制代码
/// # 隐藏设置代码
///
/// ```
/// # use my_crate::Config;
/// let config = Config::new();
/// assert!(config.is_valid());
/// ```
pub struct Config {
    // ...
}

文档测试说明

技巧 说明 示例
# 前缀 隐藏代码行 # use my_crate::Foo;
should_panic 期望 panic /// ```should_panic
ignore 跳过测试 /// ```ignore
no_run 编译但不运行 /// ```no_run

三、Mock 与测试桩

3.1 使用 mockall

  mockall 是 Rust 流行的 Mock 框架。

Cargo.toml 依赖

toml 复制代码
[dev-dependencies]
mockall = "0.11"
rust 复制代码
use mockall::automock;

#[automock]
trait Database {
    fn get_user(&self, id: u32) -> Option<String>;
    fn save_user(&self, id: u32, name: &str) -> bool;
}

struct Service {
    db: Box<dyn Database>,
}

impl Service {
    fn new(db: Box<dyn Database>) -> Self {
        Self { db }
    }

    fn get_user_name(&self, id: u32) -> Option<String> {
        self.db.get_user(id)
    }
}

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

    #[test]
    fn test_get_user_name() {
        let mut mock_db = MockDatabase::new();
        mock_db.expect_get_user()
            .with(mockall::predicate::eq(1))
            .returning(|_| Some("Alice".to_string()));

        let service = Service::new(Box::new(mock_db));
        assert_eq!(service.get_user_name(1), Some("Alice".to_string()));
    }
}

3.2 测试桩模式

rust 复制代码
// 定义 trait
pub trait HttpClient {
    fn get(&self, url: &str) -> Result<String, String>;
}

// 生产实现
pub struct RealClient;
impl HttpClient for RealClient {
    fn get(&self, url: &str) -> Result<String, String> {
        // 实际 HTTP 请求
        unimplemented!()
    }
}

// 测试桩
pub struct StubClient;
impl HttpClient for StubClient {
    fn get(&self, url: &str) -> Result<String, String> {
        Ok("stubbed response".to_string())
    }
}

Mock 与 Stub 对比

特性 Mock Stub
行为验证 验证调用次数、参数 仅返回固定值
复杂度 较高 较低
适用场景 复杂交互 简单依赖
维护成本 较高 较低

四、性能测试 Benchmark

4.1 使用 criterion

  criterion 是 Rust 标准的 Benchmark 框架。

Cargo.toml 配置

toml 复制代码
[dev-dependencies]
criterion = { version = "0.5", features = ["html_reports"] }

[[bench]]
name = "my_benchmark"
harness = false
rust 复制代码
// benches/my_benchmark.rs
use criterion::{black_box, criterion_group, criterion_main, Criterion};

fn fibonacci(n: u64) -> u64 {
    match n {
        0 => 1,
        1 => 1,
        n => fibonacci(n - 1) + fibonacci(n - 2),
    }
}

fn criterion_benchmark(c: &mut Criterion) {
    c.bench_function("fib 20", |b| b.iter(|| fibonacci(black_box(20))));
}

criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);

运行 Benchmark

bash 复制代码
cargo bench           # 运行所有 benchmark
cargo bench -- --save-baseline  # 保存基线

4.2 Benchmark 对比

框架 说明 特点
criterion 统计基准 HTML 报告、统计分析
内置 #[bench] 简单基准 需要 nightly
iai 指令计数 不受系统负载影响

五、模糊测试 Fuzzing

5.1 使用 cargo-fuzz

  cargo-fuzz 用于发现边界条件 bug。

安装

bash 复制代码
cargo install cargo-fuzz

初始化

bash 复制代码
cargo fuzz init
rust 复制代码
// fuzz/fuzz_targets/fuzz_target_1.rs
#![no_main]
use libfuzzer_sys::fuzz_target;

fuzz_target!(|data: &[u8]| {
    if data.len() > 0 {
        my_crate::parse(data);
    }
});

运行 Fuzzing

bash 复制代码
cargo fuzz run fuzz_target_1

5.2 Fuzzing 适用场景

场景 说明 示例
解析器 解析未知输入 JSON、XML 解析
序列化 数据格式转换 serde 序列化
网络协议 处理网络数据 HTTP 解析
加密 边界条件 加密算法

六、CI/CD 集成

6.1 GitHub Actions

yaml 复制代码
# .github/workflows/ci.yml
name: CI

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions-rs/toolchain@v1
        with:
          toolchain: stable
      - run: cargo test
      - run: cargo clippy
      - run: cargo fmt --check

6.2 CI 检查项

检查项 命令 说明
测试 cargo test 运行所有测试
Clippy cargo clippy 代码检查
格式化 cargo fmt --check 格式检查
文档 cargo doc 文档生成
安全审计 cargo audit 依赖安全
覆盖率 cargo tarpaulin 测试覆盖率

6.3 测试覆盖率

bash 复制代码
# 安装
cargo install cargo-tarpaulin

# 运行
cargo tarpaulin --out Html

💡 综合实战案例

实战:完整测试体系

rust 复制代码
// src/lib.rs
pub struct Calculator;

impl Calculator {
    pub fn add(a: i32, b: i32) -> i32 {
        a + b
    }

    pub fn divide(a: i32, b: i32) -> Result<i32, String> {
        if b == 0 {
            Err("Division by zero".to_string())
        } else {
            Ok(a / b)
        }
    }
}

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

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

    #[test]
    fn test_divide() {
        assert_eq!(Calculator::divide(10, 2), Ok(5));
    }

    #[test]
    fn test_divide_by_zero() {
        assert!(Calculator::divide(10, 0).is_err());
    }
}
rust 复制代码
// tests/integration_test.rs
use my_crate::Calculator;

#[test]
fn test_calculator_integration() {
    let result = Calculator::add(
        Calculator::add(1, 2),
        Calculator::add(3, 4)
    );
    assert_eq!(result, 10);
}

项目知识点

  • 单元测试(#[test]
  • 集成测试(tests/ 目录)
  • 错误处理测试
  • 断言宏使用

❓ 常见问题 FAQ

Q1:单元测试和集成测试有什么区别?

  A:主要区别:

  • 单元测试在 src/ 内,可访问私有项
  • 集成测试在 tests/ 目录,仅测试公共 API
  • 单元测试测试内部实现,集成测试测试外部接口

Q2:什么时候使用 Mock?

  A:以下场景推荐使用 Mock:

  1. 依赖外部服务(数据库、HTTP)
  2. 需要验证调用次数和参数
  3. 测试复杂交互逻辑
  4. 隔离测试环境

Q3:如何提高测试覆盖率?

  A:提高覆盖率技巧:

  1. 使用 cargo tarpaulin 检查覆盖率
  2. 编写边界条件测试
  3. 测试错误路径
  4. 使用 Fuzzing 发现遗漏

Q4:Benchmark 和测试有什么区别?

  A:区别:

  • 测试验证正确性,Benchmark 测量性能
  • 测试使用 cargo test,Benchmark 使用 cargo bench
  • 测试关注功能,Benchmark 关注速度

Q5:如何在 CI 中运行测试?

  A:使用 GitHub Actions:

  1. 创建 .github/workflows/ci.yml
  2. 配置 cargo testcargo clippycargo fmt
  3. 推送到 GitHub 自动运行

📝 学习资源与建议

学习建议

  1. 测试驱动开发 :先写测试,再写实现

  2. 覆盖边界条件 :测试正常和异常路径

  3. 使用 Mock 隔离 :避免依赖外部服务

  4. 定期 Benchmark :监控性能变化

  5. CI/CD 集成:自动化测试流程

官方资源

练习平台


📚 参考资料

相关推荐
传奇开心果编程11 小时前
【Xilem 0.4 基础语法学与练】第15课:状态管理与 memoize 性能优化
学习·rust·前端框架
qq_4523962318 小时前
第三篇:《变量、类型与函数:Rust 的“基本盘”》
开发语言·后端·rust
传奇开心果编程18 小时前
【xilem0.4基础语法学与练】第22课:on_click / on_change 与手势系统的实战
学习·rust·前端框架
对象存储与RustFS1 天前
用 Restic 把本地备份存进 RustFS:S3 兼容仓库实战
后端·rust·开源
yume_sibai1 天前
07-Rust 异步编程完全指南(async/await + Tokio + Future + 并发原语 + 异步流)
开发语言·后端·rust
qq_452396231 天前
第二篇:《环境搭建与 Hello World:Cargo、rustc 与工具链》
rust
ChampaignWolf1 天前
Joule Unit Test 深度集成:ABAP 单元测试的 AI 六件套全解析
人工智能·单元测试·sap·abap·joule·单元测试ai
川石课堂软件测试1 天前
涨薪技术|Prometheus之HTTP API中使用PromQL
网络协议·测试工具·jmeter·http·单元测试·postman·prometheus