Integration Testing

The tests Directory

The tests directory is a special top-level directory placed alongside Cargo.toml and src/ that Cargo automatically scans for integration test files. Every top-level .rs file placed directly inside tests/ is compiled by Cargo as a standalone crate that links against your package's library target (src/lib.rs).

my_package/
├── Cargo.toml
├── src/
│   └── lib.rs               <-- Compiled first as library `my_package`
└── tests/
    ├── auth_flow.rs         <-- Compiled as standalone test binary #1
    └── billing_flow.rs      <-- Compiled as standalone test binary #2

How Cargo Compiles Files in tests/

When you run cargo test:

  1. Cargo compiles src/lib.rs as a library crate.
  2. For each tests/<name>.rs file, Cargo invokes rustc --test tests/<name>.rs --extern my_package=..., producing a separate executable binary per file.
  3. Because files inside tests/ are never compiled during cargo build, you do not write #[cfg(test)] at the top of files in tests/. Every #[test] function at the top level of tests/auth_flow.rs is discovered and run automatically.
// File: tests/auth_flow.rs (links against `my_package` as an external crate)
mod my_package {
    pub fn issue_token(user_id: u64) -> String {
        format!("tok_{user_id}_v1")
    }

    pub fn validate_token(token: &str) -> Option<u64> {
        let rest = token.strip_prefix("tok_")?.strip_suffix("_v1")?;
        rest.parse().ok()
    }
}

#[test]
fn round_trips_issued_token() {
    let tok = my_package::issue_token(42);
    assert_eq!(my_package::validate_token(&tok), Some(42));
}

#[test]
fn rejects_tampered_suffix() {
    assert_eq!(my_package::validate_token("tok_42_v2"), None);
}

fn main() {
    let tok = my_package::issue_token(42);
    println!("Issued token: {tok}, valid user: {:?}", my_package::validate_token(&tok));
}
Issued token: tok_42_v1, valid user: Some(42)

Running a Single Integration Test File

When a project has multiple files in tests/, you can compile and run just one integration test binary using cargo test --test <filename_without_rs>:

cargo test --test auth_flow
     Running tests/auth_flow.rs (target/debug/deps/auth_flow-9a8b7c6d5e4f)

running 2 tests
test rejects_tampered_suffix ... ok
test round_trips_issued_token ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Custom Integration Test Targets in Cargo.toml

By default, Cargo auto-discovers every tests/*.rs file (autotests = true). If an integration test requires a custom harness (for example, harness = false for custom benchmark or snapshot runners) or specific required features (required-features = ["postgres"]), you can declare a [[test]] section in Cargo.toml:

[[test]]
name = "postgres_integration"
path = "tests/postgres_integration.rs"
required-features = ["postgres-backend"]

When required-features is set, Cargo skips building and running postgres_integration unless --features postgres-backend (or --all-features) is enabled.