affaan-m/ECC/docs/zh-CN/skills/rust-testing/SKILL.md
rust-testing
Use it for testing tasks; the detail page covers purpose, installation, and practical steps.
- Source repository stars
- 234,327
- Declared platforms
- 0
- Static risk flags
- 1
- Last source update
- 2026-07-27
- Source checked
- 2026-07-28
Decision brief
What it does—and where it fits
遵循 TDD 方法论编写可靠、可维护测试的全面 Rust 测试模式。
Not for
- Tasks that require unconfirmed production actions or broad system permissions.
- Environments where the pinned source and install steps cannot be inspected.
Compatibility matrix
Platform support, with evidence labels
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Not declared | No explicit evidence | Portability before use |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
Inspect first. Install second.
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/affaan-m/ECC --skill "docs/zh-CN/skills/rust-testing"Inspect the Agent Skill "rust-testing" from https://github.com/affaan-m/ECC/blob/4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38/docs/zh-CN/skills/rust-testing/SKILL.md at commit 4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
What the source asks the agent to do
- 01
何时使用
编写新的 Rust 函数、方法或特征 为现有代码添加测试覆盖率 为性能关键代码创建基准测试 为输入验证实现基于属性的测试 在 Rust 项目中遵循 TDD 工作流
编写新的 Rust 函数、方法或特征为现有代码添加测试覆盖率为性能关键代码创建基准测试 - 02
工作原理
1. 识别目标代码 — 找到要测试的函数、特征或模块 2. 编写测试 — 在 [cfg(test)] 模块中使用 [test],使用 rstest 进行参数化测试,或使用 proptest 进行基于属性的测试 3. 模拟依赖项 — 使用 mockall 来隔离被测单元 4. 运行测试 (RED) — 验证测试是否按预期失败 5. 实现 (GREEN) — 编写最少代码以通过测试 6. 重构 — 改进代码同时保持测试通过 7. 检查覆盖率 — 使用 cargo-llvm-cov,目标 80% 以上
识别目标代码 — 找到要测试的函数、特征或模块编写测试 — 在 [cfg(test)] 模块中使用 [test],使用 rstest 进行参数化测试,或使用 proptest 进行基于属性的测试模拟依赖项 — 使用 mockall 来隔离被测单元 - 03
Rust 的 TDD 工作流
Review the “Rust 的 TDD 工作流” section in the pinned source before continuing.
Review and apply the “Rust 的 TDD 工作流” source section. - 04
RED-GREEN-REFACTOR 循环
Review the “RED-GREEN-REFACTOR 循环” section in the pinned source before continuing.
Review and apply the “RED-GREEN-REFACTOR 循环” source section. - 05
Rust 中的分步 TDD
Review the “Rust 中的分步 TDD” section in the pinned source before continuing.
Review and apply the “Rust 中的分步 TDD” source section.
Permission review
Static risk signals and limitations
Runs scripts
The documentation asks the agent to run terminal commands or scripts.
cargo llvm-cov # SummaryRuns scripts
The documentation asks the agent to run terminal commands or scripts.
cargo llvm-cov --html # HTML reportEvidence record
Why each signal appears
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 78/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 234,327 | Source | Repository attention, not individual Skill quality |
| Compatibility | 0 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
Provenance and original SKILL.md
- Repository
- affaan-m/ECC
- Skill path
- docs/zh-CN/skills/rust-testing/SKILL.md
- Commit
- 4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38
- License
- MIT
- Collected
- 2026-07-28
- Default branch
- main
View the original SKILL.md
Rust 测试模式
遵循 TDD 方法论编写可靠、可维护测试的全面 Rust 测试模式。
何时使用
- 编写新的 Rust 函数、方法或特征
- 为现有代码添加测试覆盖率
- 为性能关键代码创建基准测试
- 为输入验证实现基于属性的测试
- 在 Rust 项目中遵循 TDD 工作流
工作原理
- 识别目标代码 — 找到要测试的函数、特征或模块
- 编写测试 — 在
#[cfg(test)]模块中使用#[test],使用 rstest 进行参数化测试,或使用 proptest 进行基于属性的测试 - 模拟依赖项 — 使用 mockall 来隔离被测单元
- 运行测试 (RED) — 验证测试是否按预期失败
- 实现 (GREEN) — 编写最少代码以通过测试
- 重构 — 改进代码同时保持测试通过
- 检查覆盖率 — 使用 cargo-llvm-cov,目标 80% 以上
Rust 的 TDD 工作流
RED-GREEN-REFACTOR 循环
RED → 先写一个失败的测试
GREEN → 编写最少代码使测试通过
REFACTOR → 重构代码,同时保持测试通过
REPEAT → 继续下一个需求
Rust 中的分步 TDD
// RED: Write test first, use todo!() as placeholder
pub fn add(a: i32, b: i32) -> i32 { todo!() }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add() { assert_eq!(add(2, 3), 5); }
}
// cargo test → panics at 'not yet implemented'
// GREEN: Replace todo!() with minimal implementation
pub fn add(a: i32, b: i32) -> i32 { a + b }
// cargo test → PASS, then REFACTOR while keeping tests green
单元测试
模块级测试组织
// src/user.rs
pub struct User {
pub name: String,
pub email: String,
}
impl User {
pub fn new(name: impl Into<String>, email: impl Into<String>) -> Result<Self, String> {
let email = email.into();
if !email.contains('@') {
return Err(format!("invalid email: {email}"));
}
Ok(Self { name: name.into(), email })
}
pub fn display_name(&self) -> &str {
&self.name
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn creates_user_with_valid_email() {
let user = User::new("Alice", "alice@example.com").unwrap();
assert_eq!(user.display_name(), "Alice");
assert_eq!(user.email, "alice@example.com");
}
#[test]
fn rejects_invalid_email() {
let result = User::new("Bob", "not-an-email");
assert!(result.is_err());
assert!(result.unwrap_err().contains("invalid email"));
}
}
断言宏
assert_eq!(2 + 2, 4); // Equality
assert_ne!(2 + 2, 5); // Inequality
assert!(vec![1, 2, 3].contains(&2)); // Boolean
assert_eq!(value, 42, "expected 42 but got {value}"); // Custom message
assert!((0.1_f64 + 0.2 - 0.3).abs() < f64::EPSILON); // Float comparison
错误与 Panic 测试
测试 Result 返回值
#[test]
fn parse_returns_error_for_invalid_input() {
let result = parse_config("}{invalid");
assert!(result.is_err());
// Assert specific error variant
let err = result.unwrap_err();
assert!(matches!(err, ConfigError::ParseError(_)));
}
#[test]
fn parse_succeeds_for_valid_input() -> Result<(), Box<dyn std::error::Error>> {
let config = parse_config(r#"{"port": 8080}"#)?;
assert_eq!(config.port, 8080);
Ok(()) // Test fails if any ? returns Err
}
测试 Panic
#[test]
#[should_panic]
fn panics_on_empty_input() {
process(&[]);
}
#[test]
#[should_panic(expected = "index out of bounds")]
fn panics_with_specific_message() {
let v: Vec<i32> = vec![];
let _ = v[0];
}
集成测试
文件结构
my_crate/
├── src/
│ └── lib.rs
├── tests/ # 集成测试
│ ├── api_test.rs # 每个文件都是一个独立的测试二进制文件
│ ├── db_test.rs
│ └── common/ # 共享测试工具
│ └── mod.rs
编写集成测试
// tests/api_test.rs
use my_crate::{App, Config};
#[test]
fn full_request_lifecycle() {
let config = Config::test_default();
let app = App::new(config);
let response = app.handle_request("/health");
assert_eq!(response.status, 200);
assert_eq!(response.body, "OK");
}
异步测试
使用 Tokio
#[tokio::test]
async fn fetches_data_successfully() {
let client = TestClient::new().await;
let result = client.get("/data").await;
assert!(result.is_ok());
assert_eq!(result.unwrap().items.len(), 3);
}
#[tokio::test]
async fn handles_timeout() {
use std::time::Duration;
let result = tokio::time::timeout(
Duration::from_millis(100),
slow_operation(),
).await;
assert!(result.is_err(), "should have timed out");
}
测试组织模式
使用 rstest 进行参数化测试
use rstest::{rstest, fixture};
#[rstest]
#[case("hello", 5)]
#[case("", 0)]
#[case("rust", 4)]
fn test_string_length(#[case] input: &str, #[case] expected: usize) {
assert_eq!(input.len(), expected);
}
// Fixtures
#[fixture]
fn test_db() -> TestDb {
TestDb::new_in_memory()
}
#[rstest]
fn test_insert(test_db: TestDb) {
test_db.insert("key", "value");
assert_eq!(test_db.get("key"), Some("value".into()));
}
测试辅助函数
#[cfg(test)]
mod tests {
use super::*;
/// Creates a test user with sensible defaults.
fn make_user(name: &str) -> User {
User::new(name, &format!("{name}@test.com")).unwrap()
}
#[test]
fn user_display() {
let user = make_user("alice");
assert_eq!(user.display_name(), "alice");
}
}
使用 proptest 进行基于属性的测试
基本属性测试
use proptest::prelude::*;
proptest! {
#[test]
fn encode_decode_roundtrip(input in ".*") {
let encoded = encode(&input);
let decoded = decode(&encoded).unwrap();
assert_eq!(input, decoded);
}
#[test]
fn sort_preserves_length(mut vec in prop::collection::vec(any::<i32>(), 0..100)) {
let original_len = vec.len();
vec.sort();
assert_eq!(vec.len(), original_len);
}
#[test]
fn sort_produces_ordered_output(mut vec in prop::collection::vec(any::<i32>(), 0..100)) {
vec.sort();
for window in vec.windows(2) {
assert!(window[0] <= window[1]);
}
}
}
自定义策略
use proptest::prelude::*;
fn valid_email() -> impl Strategy<Value = String> {
("[a-z]{1,10}", "[a-z]{1,5}")
.prop_map(|(user, domain)| format!("{user}@{domain}.com"))
}
proptest! {
#[test]
fn accepts_valid_emails(email in valid_email()) {
assert!(User::new("Test", &email).is_ok());
}
}
使用 mockall 进行模拟
基于特征的模拟
use mockall::{automock, predicate::eq};
#[automock]
trait UserRepository {
fn find_by_id(&self, id: u64) -> Option<User>;
fn save(&self, user: &User) -> Result<(), StorageError>;
}
#[test]
fn service_returns_user_when_found() {
let mut mock = MockUserRepository::new();
mock.expect_find_by_id()
.with(eq(42))
.times(1)
.returning(|_| Some(User { id: 42, name: "Alice".into() }));
let service = UserService::new(Box::new(mock));
let user = service.get_user(42).unwrap();
assert_eq!(user.name, "Alice");
}
#[test]
fn service_returns_none_when_not_found() {
let mut mock = MockUserRepository::new();
mock.expect_find_by_id()
.returning(|_| None);
let service = UserService::new(Box::new(mock));
assert!(service.get_user(99).is_none());
}
文档测试
可执行的文档
/// Adds two numbers together.
///
/// # Examples
///
/// ```
/// use my_crate::add;
///
/// assert_eq!(add(2, 3), 5);
/// assert_eq!(add(-1, 1), 0);
/// ```
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
/// Parses a config string.
///
/// # Errors
///
/// Returns `Err` if the input is not valid TOML.
///
/// ```no_run
/// use my_crate::parse_config;
///
/// let config = parse_config(r#"port = 8080"#).unwrap();
/// assert_eq!(config.port, 8080);
/// ```
///
/// ```no_run
/// use my_crate::parse_config;
///
/// assert!(parse_config("}{invalid").is_err());
/// ```
pub fn parse_config(input: &str) -> Result<Config, ParseError> {
todo!()
}
使用 Criterion 进行基准测试
# Cargo.toml
[dev-dependencies]
criterion = { version = "0.5", features = ["html_reports"] }
[[bench]]
name = "benchmark"
harness = false
// benches/benchmark.rs
use criterion::{black_box, criterion_group, criterion_main, Criterion};
fn fibonacci(n: u64) -> u64 {
match n {
0 | 1 => n,
_ => fibonacci(n - 1) + fibonacci(n - 2),
}
}
fn bench_fibonacci(c: &mut Criterion) {
c.bench_function("fib 20", |b| b.iter(|| fibonacci(black_box(20))));
}
criterion_group!(benches, bench_fibonacci);
criterion_main!(benches);
测试覆盖率
运行覆盖率
# Install: cargo install cargo-llvm-cov (or use taiki-e/install-action in CI)
cargo llvm-cov # Summary
cargo llvm-cov --html # HTML report
cargo llvm-cov --lcov > lcov.info # LCOV format for CI
cargo llvm-cov --fail-under-lines 80 # Fail if below threshold
覆盖率目标
| 代码类型 | 目标 |
|---|---|
| 关键业务逻辑 | 100% |
| 公共 API | 90%+ |
| 通用代码 | 80%+ |
| 生成的 / FFI 绑定 | 排除 |
测试命令
cargo test # Run all tests
cargo test -- --nocapture # Show println output
cargo test test_name # Run tests matching pattern
cargo test --lib # Unit tests only
cargo test --test api_test # Integration tests only
cargo test --doc # Doc tests only
cargo test --no-fail-fast # Don't stop on first failure
cargo test -- --ignored # Run ignored tests
最佳实践
应该做:
- 先写测试 (TDD)
- 使用
#[cfg(test)]模块进行单元测试 - 测试行为,而非实现
- 使用描述性测试名称来解释场景
- 为了更好的错误信息,优先使用
assert_eq!而非assert! - 在返回
Result的测试中使用?以获得更清晰的错误输出 - 保持测试独立 — 没有共享的可变状态
不应该做:
- 在可以测试
Result::is_err()时使用#[should_panic] - 模拟所有内容 — 在可行时优先考虑集成测试
- 忽略不稳定的测试 — 修复或隔离它们
- 在测试中使用
sleep()— 使用通道、屏障或tokio::time::pause() - 跳过错误路径测试
CI 集成
# GitHub Actions
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy, rustfmt
- name: Check formatting
run: cargo fmt --check
- name: Clippy
run: cargo clippy -- -D warnings
- name: Run tests
run: cargo test
- uses: taiki-e/install-action@cargo-llvm-cov
- name: Coverage
run: cargo llvm-cov --fail-under-lines 80
记住:测试就是文档。它们展示了你的代码应如何使用。清晰编写并保持更新。
Alternatives
Compare before choosing
affaan-m/ECC
rust-testing
Rust testing patterns including unit tests, integration tests, async testing, property-based testing, mocking, and coverage. Follows TDD methodology.
affaan-m/ECC
rust-testing
Patrones de pruebas en Rust incluyendo pruebas unitarias, de integración, async, basadas en propiedades, mocking y cobertura. Sigue la metodología TDD.
affaan-m/ECC
rust-testing
Rust testing patterns including unit tests, integration tests, async testing, property-based testing, mocking, and coverage. Follows TDD methodology.
affaan-m/ECC
rust-testing
Use it for testing tasks; the detail page covers purpose, installation, and practical steps.