Unit vs Integration Tests
Unit tests exercise one module in isolation inside src/. Integration tests compile as separate crates in tests/ and call only the public API, mirroring how downstream users depend on your crate.
Busca en todas las páginas de la documentación
Unit tests exercise one module in isolation inside src/. Integration tests compile as separate crates in tests/ and call only the public API, mirroring how downstream users depend on your crate.
// src/lib.rs - unit test
#[cfg(test)]
mod tests {
#[test]
fn internal_helper() { /* uses private fn */ }
}// tests/api_smoke.rs - integration test
use my_crate::Client;
#[test]
fn creates_client() {
let _ = Client::new("http://localhost");
}When to reach for this: Unit tests for logic; integration tests for wiring, HTTP handlers, and DB boundaries.
my_service/
├── src/
│ ├── lib.rs
│ ├── domain.rs
│ └── api.rs
└── tests/
├── health.rs
└── orders.rs
// tests/orders.rs
use axum::body::Body;
use axum::http::{Request, StatusCode};
use tower::ServiceExt;
use my_service::app;
#[tokio::test]
async fn post_order_returns_201() {
let app = app();
let response = app
.oneshot(Request::builder().method("POST").uri("/orders").body(Body::empty()).unwrap())
.await
.unwrap();
assert_eq!(response.status(), StatusCode::CREATED);
}What this demonstrates:
use my_service::...)pub items are reachable#[tokio::test]| Aspect | Unit (#[cfg(test)]) | Integration (tests/) |
|---|---|---|
| Location | Inside src/**/*.rs | tests/*.rs |
| Visibility | Private API | Public API only |
| Compile unit | Same crate | Separate crate per file |
| Speed | Faster | Slower (links full lib) |
Each tests/*.rs is its own crate. Share helpers via tests/common/mod.rs (not auto-discovered as a test) or a tests/common.rs included with mod common;.
pub API drifts. Fix: integration tests for every public endpoint or type.#[serial_test::serial] or isolate state per test.tests/support module (Test Organization).| Alternative | Use When | Don't Use When |
|---|---|---|
| Doc tests | Examples in docs must compile | Complex multi-crate wiring |
#[cfg(test)] in tests/common | Shared fixtures | Need to test private helpers |
In-crate mod tests only | Pure algorithm crates | HTTP/CLI boundary testing |
Many unit tests for pure logic; fewer integration tests covering critical user paths and error handling.
Yes. The test crate links against your lib and can use dev-deps declared in the main Cargo.toml.
Only tests/*.rs at the top level are test crates. Submodules are support code.
Extract logic to a library crate; integration tests import the lib. Binaries stay thin main wrappers.
Place under the specific package's tests/ or a dedicated integration-tests member crate depending on scope.
Yes by default. Use --test-threads=1 when tests contend on ports or files.
cargo test --test orders runs one integration file.
Extract pure logic to functions with unit tests; keep one integration test per route for status codes.
Use for docker-required tests; run with cargo test -- --ignored in nightly CI.
cargo nextest run respects the same unit/integration split with faster scheduling.
cargo test#[tokio::test]Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.
Revisado por Chris St. John·Última actualización: 16 jul 2026