test-runner
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTest Runner
测试运行器
Execute and manage Rust tests for the self-learning memory project.
执行并管理自学习记忆项目的Rust测试。
Test Categories
测试分类
| Category | Command (preferred) | Fallback | Scope |
|---|---|---|---|
| Unit | | | Individual functions |
| Integration | | | End-to-end workflows |
| Doc | | (nextest unsupported) | Documentation examples |
| All | | | Complete validation |
| Mutation | | — | Test effectiveness |
| Snapshot | | — | Output regression |
| 分类 | 推荐命令 | 备选命令 | 测试范围 |
|---|---|---|---|
| 单元测试 | | | 独立函数 |
| 集成测试 | | | 端到端工作流 |
| 文档测试 | | (nextest不支持) | 文档示例 |
| 全部测试 | | | 完整验证 |
| 突变测试 | | — | 测试有效性 |
| 快照测试 | | — | 输出回归 |
Execution Strategy
执行策略
Step 1: Quick Check (Unit Tests)
步骤1:快速检查(单元测试)
bash
cargo nextest run --lib- Fast feedback (< 30s), per-test process isolation
- Catch basic logic errors
bash
cargo nextest run --lib- 快速反馈(< 30秒),每个测试独立进程隔离
- 捕获基础逻辑错误
Step 2: Integration Tests
步骤2:集成测试
bash
cargo nextest run --test '*'- Tests database interactions
- Requires Turso/redb setup
bash
cargo nextest run --test '*'- 测试数据库交互
- 需要Turso/redb环境配置
Step 3: Full Suite
步骤3:完整测试套件
bash
cargo nextest run --all
cargo test --doc # doctests separately (nextest limitation)- Complete validation before commit
bash
cargo nextest run --all
cargo test --doc # 文档测试单独执行(nextest限制)- 提交前的完整验证
Step 4: Mutation Testing (Periodic)
步骤4:突变测试(定期执行)
bash
cargo mutants -p memory-core --timeout 120 --jobs 4 -- --lib- Verifies test suite catches real bugs
- Run nightly or before releases (ADR-033)
bash
cargo mutants -p memory-core --timeout 120 --jobs 4 -- --lib- 验证测试套件能否发现真实bug
- 在夜间或发布前运行(ADR-033)
Troubleshooting
问题排查
Async/Await Issues
Async/Await问题
Symptom: Test hangs
rust
#[tokio::test]
async fn test_async() {
let result = async_fn().await; // Don't forget .await
}症状:测试挂起
rust
#[tokio::test]
async fn test_async() {
let result = async_fn().await; // 不要忘记.await
}Database Connection
数据库连接
Symptom: Connection refused
- Check TURSO_URL, TURSO_TOKEN
- Use test database
症状:连接被拒绝
- 检查TURSO_URL、TURSO_TOKEN配置
- 使用测试数据库
Race Conditions
竞态条件
Symptom: Intermittent failures
bash
cargo test -- --test-threads=1症状:间歇性失败
bash
cargo test -- --test-threads=1redb Lock Errors
redb锁错误
Symptom: "Database is locked"
- Use separate DB per test
- Close transactions promptly
症状:"Database is locked"
- 为每个测试使用独立数据库
- 及时关闭事务
Coverage
覆盖率
bash
cargo install cargo-llvm-cov
cargo llvm-cov --html --output-dir coveragebash
cargo install cargo-llvm-cov
cargo llvm-cov --html --output-dir coverageBest Practices
最佳实践
- Isolation: Each test independent
- Cleanup: Remove test data
- Speed: < 1s per unit test
- Naming:
test_<function>_<scenario>_<expected> - AAA pattern: Arrange-Act-Assert in every test
- Single responsibility: Each test verifies ONE behavior
- 隔离性:每个测试相互独立
- 清理:移除测试数据
- 速度:每个单元测试<1秒
- 命名:
test_<函数>_<场景>_<预期结果> - AAA模式:每个测试遵循Arrange-Act-Assert(准备-执行-断言)
- 单一职责:每个测试仅验证一种行为
Advanced: Async Testing Patterns
进阶:异步测试模式
rust
// Time-based testing (paused clock)
#[tokio::test(start_paused = true)]
async fn test_timeout_behavior() {
let start = tokio::time::Instant::now();
tokio::time::sleep(Duration::from_secs(5)).await;
assert!(start.elapsed().as_millis() < 100);
}
// Concurrent operations
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
async fn test_concurrent_episodes() {
let memory = Arc::new(setup_memory().await);
let handles: Vec<_> = (0..10).map(|i| {
let mem = memory.clone();
tokio::spawn(async move {
mem.start_episode(format!("Task {}", i), ctx, type_).await
})
}).collect();
let results = futures::future::join_all(handles).await;
assert_eq!(results.len(), 10);
}rust
// 基于时间的测试(暂停时钟)
#[tokio::test(start_paused = true)]
async fn test_timeout_behavior() {
let start = tokio::time::Instant::now();
tokio::time::sleep(Duration::from_secs(5)).await;
assert!(start.elapsed().as_millis() < 100);
}
// 并发操作
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
async fn test_concurrent_episodes() {
let memory = Arc::new(setup_memory().await);
let handles: Vec<_> = (0..10).map(|i| {
let mem = memory.clone();
tokio::spawn(async move {
mem.start_episode(format!("Task {}", i), ctx, type_).await
})
}).collect();
let results = futures::future::join_all(handles).await;
assert_eq!(results.len(), 10);
}Common Async Pitfalls
常见异步陷阱
| Bad | Good |
|---|---|
| |
| |
| Single-threaded for concurrency | |
| 错误做法 | 正确做法 |
|---|---|
| |
| |
| 单线程处理并发 | |
nextest Profiles (.config/nextest.toml)
nextest配置文件(.config/nextest.toml)
toml
[profile.default]
retries = 0
slow-timeout = { period = "60s", terminate-after = 2 }
fail-fast = false
[profile.ci]
retries = 2
slow-timeout = { period = "30s", terminate-after = 3 }
failure-output = "immediate-final"
junit.path = "target/nextest/ci/junit.xml"
[profile.nightly]
retries = 3
slow-timeout = { period = "120s", terminate-after = 2 }bash
cargo nextest run # default profile
cargo nextest run --profile ci # CI with retries + JUnit
cargo nextest run --profile nightly # nightly with extended timeoutstoml
[profile.default]
retries = 0
slow-timeout = { period = "60s", terminate-after = 2 }
fail-fast = false
[profile.ci]
retries = 2
slow-timeout = { period = "30s", terminate-after = 3 }
failure-output = "immediate-final"
junit.path = "target/nextest/ci/junit.xml"
[profile.nightly]
retries = 3
slow-timeout = { period = "120s", terminate-after = 2 }bash
cargo nextest run # 使用默认配置
cargo nextest run --profile ci # CI环境(带重试+JUnit报告)
cargo nextest run --profile nightly # 夜间构建(带延长超时)Snapshot Testing (insta)
快照测试(insta)
rust
#[test]
fn test_mcp_tool_response() {
let response = build_tool_response("search_patterns", ¶ms);
insta::assert_json_snapshot!(response);
}bash
cargo insta test # run snapshot tests
cargo insta review # accept/reject changesrust
#[test]
fn test_mcp_tool_response() {
let response = build_tool_response("search_patterns", ¶ms);
insta::assert_json_snapshot!(response);
}bash
cargo insta test # 运行快照测试
cargo insta review # 接受/拒绝快照变更Property-Based Testing
属性化测试
rust
proptest! {
#[test]
fn test_episode_id_uniqueness(
tasks in prop::collection::vec(any::<String>(), 1..100)
) {
let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async {
let memory = setup_memory().await;
let mut ids = HashSet::new();
for desc in tasks {
let id = memory.start_episode(desc, ctx, type_).await;
prop_assert!(ids.insert(id));
}
});
}
}rust
proptest! {
#[test]
fn test_episode_id_uniqueness(
tasks in prop::collection::vec(any::<String>(), 1..100)
) {
let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async {
let memory = setup_memory().await;
let mut ids = HashSet::new();
for desc in tasks {
let id = memory.start_episode(desc, ctx, type_).await;
prop_assert!(ids.insert(id));
}
});
}
}Advanced: Episodic Memory Testing
进阶:情景记忆测试
rust
#[tokio::test]
async fn test_complete_episode_lifecycle() {
let memory = setup_memory().await;
let id = memory.start_episode("Test task", ctx, TaskType::CodeGen).await;
memory.log_execution_step(id.clone(), step1).await;
memory.complete_episode(id.clone(), TaskOutcome::Success, None).await?;
let episode = memory.get_episode(&id).await?;
assert_eq!(episode.outcome, TaskOutcome::Success);
}rust
#[tokio::test]
async fn test_complete_episode_lifecycle() {
let memory = setup_memory().await;
let id = memory.start_episode("Test task", ctx, TaskType::CodeGen).await;
memory.log_execution_step(id.clone(), step1).await;
memory.complete_episode(id.clone(), TaskOutcome::Success, None).await?;
let episode = memory.get_episode(&id).await?;
assert_eq!(episode.outcome, TaskOutcome::Success);
}Performance Targets
性能指标
| Operation | Target | Actual |
|---|---|---|
| Episode Creation | < 50ms | ~2.5 µs |
| Step Logging | < 20ms | ~1.1 µs |
| Pattern Extraction | < 1000ms | ~10.4 µs |
| Memory Retrieval | < 100ms | ~721 µs |
| 操作 | 目标 | 实际值 |
|---|---|---|
| 情景创建 | < 50ms | ~2.5 µs |
| 步骤日志记录 | < 20ms | ~1.1 µs |
| 模式提取 | < 1000ms | ~10.4 µs |
| 内存检索 | < 100ms | ~721 µs |
References
参考资料
- ADR-033: Modern Testing Strategy
- TESTING.md — Full testing guide
Consolidated from these former skills (preserved in ):
_consolidated/- — cargo-nextest, property testing, benchmarking
test-optimization - — AAA pattern, naming conventions, test quality
quality-unit-testing - — tokio test patterns, time-based testing
rust-async-testing - — episode lifecycle, pattern extraction, reward scoring tests
episodic-memory-testing
- ADR-033: Modern Testing Strategy
- TESTING.md — 完整测试指南
整合自以下旧技能(已存档于):
_consolidated/- — cargo-nextest、属性化测试、基准测试
test-optimization - — AAA模式、命名规范、测试质量
quality-unit-testing - — tokio测试模式、基于时间的测试
rust-async-testing - — 情景生命周期、模式提取、奖励评分测试
episodic-memory-testing