rust-testing

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Rust Testing and Benchmarking

Rust测试与基准测试

Based on Chapter 11 of The Rust Programming Language and the Rust Book.
基于《Rust程序设计语言》第11章和Rust Book。

Capability Boundaries

能力边界

✅ Strengths

✅ 强项

  1. Unit tests (using
    #[test]
    , organizing test modules with
    #[cfg(test)]
    )
  2. Assertion macros (
    assert!
    ,
    assert_eq!
    ,
    assert_ne!
    ,
    debug_assert!
    )
  3. Test attributes (
    #[should_panic]
    ,
    #[ignore]
    ,
    #[cfg(test)]
    )
  4. Integration tests (tests/ directory and shared modules)
  5. Documentation tests (code blocks, hidden lines with
    #
    , should_panic/no_run/ignore flags)
  6. cargo test runner (filtering, --nocapture, --test-threads, --include-ignored options)
  7. Stable Criterion benchmarks; explicitly distinguishing stable Criterion from nightly-only libtest
    #[bench]
    attribute
  8. Code coverage using cargo-llvm-cov
  9. Asynchronous race conditions, backpressure, timeouts, process/daemon models, platform matrices, and resource-constrained testing
  1. 单元测试(使用
    #[test]
    ,使用
    #[cfg(test)]
    组织测试模块)
  2. 断言宏(
    assert!
    、
    assert_eq!
    、
    assert_ne!
    、
    debug_assert!
    )
  3. 测试属性(
    #[should_panic]
    、
    #[ignore]
    、
    #[cfg(test)]
    )
  4. 集成测试(tests/目录和共享模块)
  5. 文档测试(代码块、
    #
    隐藏行、should_panic/no_run/ignore标志)
  6. cargo test 运行器(过滤、--nocapture、--test-threads、--include-ignored选项)
  7. 稳定的Criterion基准测试;明确区分稳定的Criterion和仅限nightly的libtest
    #[bench]
    属性
  8. 使用cargo-llvm-cov进行代码覆盖率
  9. 异步竞态条件、背压、超时、进程/守护进程模型、平台矩阵和资源受限测试

⚠️ Prerequisites

⚠️ 前提条件

  1. Understanding of Rust module system (rust-workspace)
  1. 理解Rust模块系统(rust-workspace)

❌ Out of Scope

❌ 不在范围内

  1. Property-based tests (
    proptest
    ) → Not currently covered
  2. Mock objects → Not currently covered
  3. Basic Rust syntax → Use
    rust-stable
    skill instead
  1. 基于属性的测试(
    proptest
    )→ 目前未涉及
  2. Mock对象 → 目前未涉及
  3. 基本Rust语法 → 请使用
    rust-stable
    skill

When to Use

使用时机

  • "Write unit tests"
  • "Where should integration tests be placed?"
  • "How do I write documentation tests?"
  • "Performance benchmarking"
  • "Check code coverage"

  • "编写单元测试"
  • "集成测试应该放在哪里?"
  • "如何编写文档测试?"
  • "性能基准测试"
  • "检查代码覆盖率"

Routing Boundary

路由边界

Use
rust-java-migration-testing
when tests must disposition a source Java suite, distinguish mirrored tests from golden/live differential evidence, add target-specific ownership/async/error/component obligations, audit coverage-chasing tests, or verify migration lifecycle/adapter/host acceptance. Keep this skill focused on general Rust test mechanics and Rust-native test architecture.
当测试必须处理源Java测试套件的分类、区分镜像测试与golden/live差分证据、添加目标特定的ownership/async/error/component义务、审计追逐覆盖率的测试,或验证迁移生命周期/适配器/宿主验收时,请使用
rust-java-migration-testing
。保持本skill专注于通用Rust测试机制和Rust原生测试架构。

Unit Tests

单元测试

rust
// src/lib.rs
pub fn add(a: i32, b: i32) -> i32 { a + b }
pub fn divide(a: i32, b: i32) -> i32 {
    if b == 0 { panic!("divide by zero"); }
    a / b
}

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

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

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

    #[test]
    #[should_panic(expected = "divide by zero")]
    fn test_divide_by_zero() {
        divide(1, 0);
    }

    #[test]
    #[ignore = "not implemented"]
    fn test_future() { unimplemented!() }
}
rust
// src/lib.rs
pub fn add(a: i32, b: i32) -> i32 { a + b }
pub fn divide(a: i32, b: i32) -> i32 {
    if b == 0 { panic!("divide by zero"); }
    a / b
}

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

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

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

    #[test]
    #[should_panic(expected = "divide by zero")]
    fn test_divide_by_zero() {
        divide(1, 0);
    }

    #[test]
    #[ignore = "not implemented"]
    fn test_future() { unimplemented!() }
}

Integration Tests

集成测试

text
my-project/
├── Cargo.toml
├── src/lib.rs
└── tests/
    ├── common/          # Test shared modules
    │   └── mod.rs
    ├── integration_test.rs
    └── api_test.rs
rust
// tests/integration_test.rs — Each file is an independent crate
use my_project::add;

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

// tests/common/mod.rs — Shared helper functions
pub fn setup() { /* ... */ }
text
my-project/
├── Cargo.toml
├── src/lib.rs
└── tests/
    ├── common/          # 测试共享模块
    │   └── mod.rs
    ├── integration_test.rs
    └── api_test.rs
rust
// tests/integration_test.rs — 每个文件是一个独立的crate
use my_project::add;

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

// tests/common/mod.rs — 共享辅助函数
pub fn setup() { /* ... */ }

Documentation Tests (doctest)

文档测试(doctest)

rust
/// Add two numbers.
///
/// ```
/// use my_crate::add;
/// assert_eq!(add(2, 3), 5);
/// ```
///
/// ```rust,should_panic
/// my_crate::divide(1, 0);
/// ```
///
/// ```rust,no_run
/// // Compile but do not run
/// loop {}
/// ```
pub fn add(a: i32, b: i32) -> i32 { a + b }
rust
/// Add two numbers.
///
/// ```
/// use my_crate::add;
/// assert_eq!(add(2, 3), 5);
/// ```
///
/// ```rust,should_panic
/// my_crate::divide(1, 0);
/// ```
///
/// ```rust,no_run
/// // Compile but do not run
/// loop {}
/// ```
pub fn add(a: i32, b: i32) -> i32 { a + b }

cargo test Commands

cargo test 命令

bash
cargo test                    # Run all tests
cargo test test_name          # Filter by name
cargo test -- --nocapture     # Show println output
cargo test -- --test-threads=1 # Single thread
cargo test -- --skip test_name # Skip specific tests
cargo test -- --ignored       # Only run #[ignore] tests
cargo test -- --include-ignored # Include ignored tests
cargo test --doc              # Run only documentation tests
cargo test -p my-crate        # Specific package
bash
cargo test                    # 运行所有测试
cargo test test_name          # 按名称过滤
cargo test -- --nocapture     # 显示println输出
cargo test -- --test-threads=1 # 单线程
cargo test -- --skip test_name # 跳过特定测试
cargo test -- --ignored       # 仅运行 #[ignore] 测试
cargo test -- --include-ignored # 包含被忽略的测试
cargo test --doc              # 仅运行文档测试
cargo test -p my-crate        # 特定包

Benchmarks

基准测试

Stable projects should prioritize Criterion. The built-in libtest
#[bench]
still relies on nightly's
#![feature(test)]
, which cannot be used as a stable default solution.
rust
// Nightly-only builtin approach (do not use for stable gatekeeping)
#![feature(test)]
extern crate test;

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

    #[bench]
    fn bench_add(b: &mut Bencher) {
        b.iter(|| add(1, 2));
    }
}

// Stable approach using criterion
// [dev-dependencies] criterion = { version = "0.5", features = ["html_reports"] }
use criterion::{black_box, Criterion};

fn bench_add(c: &mut Criterion) {
    c.bench_function("add", |b| b.iter(|| add(black_box(1), black_box(2))));
}
criterion_group!(benches, bench_add);
criterion_main!(benches);
稳定项目应优先使用Criterion。内置的libtest
#[bench]
仍依赖nightly的
#![feature(test)]
,不能作为稳定的默认解决方案。
rust
// 仅限nightly的内置方法(不要用于稳定门禁)
#![feature(test)]
extern crate test;

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

    #[bench]
    fn bench_add(b: &mut Bencher) {
        b.iter(|| add(1, 2));
    }
}

// 使用criterion的稳定方法
// [dev-dependencies] criterion = { version = "0.5", features = ["html_reports"] }
use criterion::{black_box, Criterion};

fn bench_add(c: &mut Criterion) {
    c.bench_function("add", |b| b.iter(|| add(black_box(1), black_box(2))));
}
criterion_group!(benches, bench_add);
criterion_main!(benches);

Code Coverage

代码覆盖率

bash
undefined
bash
undefined

Install

安装

cargo install cargo-llvm-cov
cargo install cargo-llvm-cov

Usage

使用

cargo llvm-cov # Run and report results cargo llvm-cov --open # Generate HTML reports cargo llvm-cov --lcov --output-path lcov.info # LCOV format output
undefined
cargo llvm-cov # 运行并报告结果 cargo llvm-cov --open # 生成HTML报告 cargo llvm-cov --lcov --output-path lcov.info # LCOV格式输出
undefined

Workflow

工作流程

  1. Prepare test environment — Ensure cargo test is available, confirm test types (unit/integration/documentation)
  2. Write unit tests — Implement #[test] functions within
    #[cfg(test)]
    modules
  3. Add integration tests — Create independent crate-type files in the tests/ directory
  4. Add documentation tests — Embed executable code blocks inside /// comments
  5. Run and debug — Use cargo test; use --nocapture to locate issues; prioritize resource isolation or test grouping for shared resources, avoiding permanent serialization of full test suites
  6. Concurrency and platform validation — Implement bounded assertions for queue limits, slow consumers, disconnections, cancellations, timeouts, and graceful shutdowns on real target platforms; run platform-specific code directly
  7. Coverage checks — Use cargo llvm-cov to verify coverage ranges
  1. 准备测试环境 — 确保cargo test可用,确认测试类型(单元/集成/文档)
  2. 编写单元测试 — 在
    #[cfg(test)]
    模块中实现#[test]函数
  3. 添加集成测试 — 在tests/目录中创建独立的crate类型文件
  4. 添加文档测试 — 在///注释中嵌入可执行代码块
  5. 运行和调试 — 使用cargo test;使用--nocapture定位问题;优先考虑资源隔离或测试分组以处理共享资源,避免永久串行化整个测试套件
  6. 并发和平台验证 — 在真实目标平台上实现队列限制、慢消费者、断连、取消、超时和优雅关闭的有界断言;直接运行特定平台代码
  7. 覆盖率检查 — 使用cargo llvm-cov验证覆盖率范围

Gotchas

注意事项

  1. Code in
    #[cfg(test)]
    modules does not compile into release builds — Helper functions should reside in tests/common/mod.rs
  2. Integration test files are independent crates — Cannot use super:: or crate:: prefixes within them
  3. Hidden lines (#) in documentation tests remain executable but invisible to the compiler
  4. cargo test runs by default in parallel; shared resource conflicts should be resolved via unique temporary directories/ports, process isolation, nextest test group limits, or local serialization only when necessary
  5. #[bench] requires #![feature(test)] — Stable Rust must use criterion instead
  6. Providing a broad timeout for async tests hides deadlock causes; also assert intermediate states, task recovery, and resource counts
  1. #[cfg(test)]
    模块中的代码不会编译进发布构建 — 辅助函数应放在tests/common/mod.rs中
  2. 集成测试文件是独立的crate — 不能在其中使用super::或crate::前缀
  3. 文档测试中的隐藏行(#)仍然可执行但对编译器不可见
  4. cargo test默认并行运行;共享资源冲突应通过唯一临时目录/端口、进程隔离、nextest测试组限制或仅在必要时本地串行化解决
  5. #[bench]需要#![feature(test)] — 稳定版Rust必须使用criterion
  6. 为异步测试提供过宽的超时会掩盖死锁原因;还应断言中间状态、任务恢复和资源计数

On-Demand Resources

按需资源

  • Test examples
  • Macro commands and command reference
  • Concurrency, daemon, and platform testing: Test for memory leaks in tasks, slow consumers, race conditions, real processes, and resource-limited parallelism when reading.
  • examples/golden-tests/
    : CI compilation and execution of doctest golden examples
  • 测试示例
  • 宏命令和命令参考
  • 并发、守护进程和平台测试:阅读时用于测试任务中的内存泄漏、慢消费者、竞态条件、真实进程和资源受限的并行。
  • examples/golden-tests/
    :CI编译和执行doctest golden示例

Official References

官方参考