一键导入
rust-testing
Use when writing unit/integration tests, setting up test infrastructure, mocking with wiremock/mockall, or designing test structure in Rust.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use when writing unit/integration tests, setting up test infrastructure, mocking with wiremock/mockall, or designing test structure in Rust.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use when designing REST API endpoints, URL structure, HTTP methods, status codes, request/response formats, pagination, SSE streaming, or OpenAPI docs in Axum.
Use when creating modules, organizing project structure, designing layered architecture (handler/service/domain/repo), dependency injection, or DDD patterns in Rust.
Use when designing PostgreSQL schemas, writing SQLx migrations, choosing data types, naming tables/columns/indexes, or writing compile-time checked queries.
Use when implementing error types, designing error hierarchies, mapping errors to HTTP responses, or reviewing error handling patterns in Rust code using thiserror and anyhow.
Use when setting up tracing, configuring log levels, writing structured logs, using spans and instrument, or handling sensitive data in Rust logs.
| name | rust-testing |
| description | Use when writing unit/integration tests, setting up test infrastructure, mocking with wiremock/mockall, or designing test structure in Rust. |
| Type | Location | Dependencies |
|---|---|---|
| Unit tests | #[cfg(test)] module in source file | None (no external deps) |
| Integration tests | tests/ directory | May need database/services |
cargo test # all tests
cargo test --lib # unit tests only
cargo test --test '*' # integration tests only
cargo test -- --nocapture # show stdout
Place in a #[cfg(test)] module at the bottom of the source file:
impl Order {
pub fn can_cancel(&self) -> bool {
matches!(self.status, OrderStatus::Pending | OrderStatus::Processing)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_can_cancel_pending_order() {
let order = Order { status: OrderStatus::Pending, ..Default::default() };
assert!(order.can_cancel());
}
}
// Format: test_{feature}_{scenario}_{expected}
fn test_place_order_with_insufficient_balance_returns_error() { }
// Or "should" style
fn should_return_error_when_balance_insufficient() { }
tests/
├── common/
│ └── mod.rs # shared helpers (setup_test_db, etc.)
├── api/
│ └── orders_test.rs
└── integration/
└── order_flow_test.rs
#[tokio::test]
async fn test_create_order_success() {
let pool = setup_test_db().await;
let server = TestServer::new(create_test_app(pool.clone()).await).unwrap();
let response = server
.post("/orders")
.add_header("Authorization", format!("Bearer {}", api_key))
.json(&json!({ "product_id": "prod-001", "quantity": 2 }))
.await;
response.assert_status(StatusCode::CREATED);
}
#[async_trait]
pub trait ExternalApiClient: Send + Sync {
async fn submit(&self, req: &SubmitRequest) -> Result<SubmitResponse, Error>;
}
// Test implementation
pub struct MockExternalApiClient {
pub responses: Arc<Mutex<Vec<Result<SubmitResponse, Error>>>>,
}
For most cases, prefer mockall over hand-written mocks — it auto-generates mock structs from traits:
use mockall::automock;
#[automock]
#[async_trait]
pub trait ExternalApiClient: Send + Sync {
async fn submit(&self, req: &SubmitRequest) -> Result<SubmitResponse, Error>;
}
#[tokio::test]
async fn test_submit_delegates_to_client() {
let mut mock = MockExternalApiClient::new();
mock.expect_submit()
.returning(|_| Ok(SubmitResponse { id: "abc-123".into() }));
let service = OrderService::new(Arc::new(mock));
let result = service.process(&request).await.unwrap();
assert_eq!(result.id, "abc-123");
}
#[tokio::test]
async fn test_external_api_client() {
let mock_server = MockServer::start().await;
Mock::given(method("POST"))
.and(path("/api/process"))
.respond_with(ResponseTemplate::new(200).set_body_json(json!({
"id": "abc-123"
})))
.mount(&mock_server)
.await;
let client = ExternalApiClient::new(&mock_server.uri());
let result = client.submit(&request).await.unwrap();
assert_eq!(result.id, "abc-123");
}
For logic with wide input ranges, consider proptest to auto-generate test cases:
use proptest::prelude::*;
proptest! {
#[test]
fn test_discount_never_exceeds_total(
price in 1u64..10_000,
discount_pct in 0u8..=100,
) {
let discounted = apply_discount(price, discount_pct);
prop_assert!(discounted <= price);
}
}
proptest is especially useful for parsers, serialization round-trips, and numeric invariants.
// WRONG: unwrap without context
let result = operation().unwrap();
// RIGHT: use expect
let result = operation().expect("operation should succeed with valid input");
// WRONG: hard-coded sleep
std::thread::sleep(Duration::from_secs(1));
// RIGHT: conditional wait with timeout
tokio::time::timeout(Duration::from_secs(5), wait_for_condition()).await;
// WRONG: tests depend on execution order
// RIGHT: each test is fully independent
#[cfg(test)] modulestests/ directory#[tokio::test]