Real-world examples of examples of testing in Rust

If you learn best by seeing code in action, you’re in the right place. This guide walks through real, practical examples of examples of testing in Rust: unit tests, integration tests, property-based tests, async tests, and more. Instead of abstract theory, we’ll focus on short, focused snippets that you can drop into your own projects today. Rust’s testing story has matured a lot since the early 1.x days. The ecosystem now includes battle-tested crates for async testing, property-based testing, and snapshot testing, and the standard `cargo test` workflow is stable and fast. In the sections below, we’ll move from basic `#[test]` functions to more advanced patterns used in production services and CLI tools. Along the way, you’ll see examples of how to organize test modules, mock dependencies, test error handling, and even test performance-sensitive code. If you’ve been looking for real examples of testing in Rust that go beyond trivial `assert_eq!(2 + 2, 4)`, this is for you.
Written by
Jamie
Published

Simple unit examples of testing in Rust inside a module

Let’s start with the kind of example of test you’ll see in almost every Rust crate: a small unit test module living next to the code it verifies.

// src/math.rs
pub fn safe_divide(a: i32, b: i32) -> Option<i32> {
    if b == 0 {
        None
    } else {
        Some(a / b)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn divides_positive_numbers() {
        assert_eq!(safe_divide(10, 2), Some(5));
    }

    #[test]
    fn returns_none_on_zero_division() {
        assert_eq!(safe_divide(10, 0), None);
    }
}

This is one of the best examples of testing in Rust for beginners:

  • The #[cfg(test)] module is compiled only when running cargo test.
  • use super::*; imports the functions from the parent module.
  • Each #[test] function is independent and can be run by name, for example: cargo test returns_none_on_zero_division.

In practice, examples of examples of testing in Rust like this help you keep tests close to the logic they validate, which makes refactoring far less risky.


Integration examples of testing in Rust with tests/ directory

As your project grows, you’ll want to test the public API as a whole, not just individual functions. Rust supports this through integration tests placed in a tests/ directory at the project root.

// src/lib.rs
pub fn add_prefix(prefix: &str, value: &str) -> String {
    format!("{}-{}", prefix, value)
}
// tests/prefix_integration.rs
use my_crate::add_prefix;

#[test]
fn prefixes_values_for_external_callers() {
    let result = add_prefix("user", "123");
    assert_eq!(result, "user-123");
}

Integration tests:

  • Use your crate like an external user would: use my_crate::....
  • Are compiled as separate crates, which catches missing pub visibility and API design issues.

For many teams, the strongest real examples of testing in Rust are these integration tests, because they validate that the crate behaves correctly from the outside, not just internally.


Async examples include testing async functions with tokio::test

Modern Rust services are often async, especially web APIs and message consumers. Here’s an example of testing in Rust using tokio to drive async code.

## Cargo.toml
[dependencies]
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
// src/client.rs
use std::time::Duration;
use tokio::time::sleep;

pub async fn fetch_message() -> String {
    // Imagine this is an HTTP call
    sleep(Duration::from_millis(10)).await;
    "hello".to_string()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn fetch_message_returns_hello() {
        let msg = fetch_message().await;
        assert_eq!(msg, "hello");
    }
}

The #[tokio::test] macro sets up a runtime automatically, so you don’t have to wire up an executor in every test. This pattern shows up in many real examples of testing in Rust web backends built with frameworks like axum or actix-web.

For more background on async programming models and concurrency, the Rust community often points to university systems courses and research. For example, MIT’s open courseware on operating systems and concurrency concepts at mit.edu can help you reason about async behavior when you design tests.


Property-based examples of testing in Rust with proptest

Sometimes you don’t just want to test a few hand-picked inputs; you want the test framework to generate many random cases and shrink failing ones. That’s where property-based testing comes in.

## Cargo.toml
[dev-dependencies]
proptest = "1"
// src/normalize.rs
pub fn normalize_whitespace(input: &str) -> String {
    input.split_whitespace().collect::<Vec<_>>().join(" ")
}

#[cfg(test)]
mod tests {
    use super::*;
    use proptest::prelude::*;

    proptest! {
        #[test]
        fn output_never_contains_double_spaces(s in "[a-zA-Z0-9\t\n ]*") {
            let normalized = normalize_whitespace(&s);
            assert!(!normalized.contains("  "));
        }
    }
}

Here, the property is simple: after normalization, there should be no double spaces. The framework generates many random strings and looks for a counterexample. This style of test is one of the best examples of testing in Rust when you’re validating invariants, parsers, or protocol implementations.

If you’re curious about the theory behind this style of testing, the Haskell QuickCheck papers and related research hosted on university sites like harvard.edu are good background reading.


Examples of testing error handling and Result types

Rust code leans heavily on Result<T, E>. It’s worth having clear examples of testing in Rust that verify both success and failure paths.

// src/parser.rs
#[derive(Debug, PartialEq)]
pub enum ParseError {
    Empty,
    InvalidFormat,
}

pub fn parse_port(input: &str) -> Result<u16, ParseError> {
    if input.trim().is_empty() {
        return Err(ParseError::Empty);
    }
    let value: u16 = input.parse().map_err(|_| ParseError::InvalidFormat)?;
    Ok(value)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn parses_valid_port() {
        assert_eq!(parse_port("8080"), Ok(8080));
    }

    #[test]
    fn errors_on_empty_input() {
        assert_eq!(parse_port("   "), Err(ParseError::Empty));
    }

    #[test]
    fn errors_on_non_numeric_input() {
        assert_eq!(parse_port("eighty"), Err(ParseError::InvalidFormat));
    }
}

These are small, but they’re the sort of examples of examples of testing in Rust that you’ll repeat endlessly in real projects: assert the exact error variant, not just that “something failed.” That discipline pays off when you’re debugging production incidents.


Examples include testing CLIs with assert_cmd and predicates

Command-line tools are a big part of the Rust ecosystem. Testing them doesn’t need to be painful.

## Cargo.toml
[dev-dependencies]
assert_cmd = "2"
predicates = "3"
``

```rust
// tests/cli.rs
use assert_cmd::Command;
use predicates::prelude::*;

#[test]
fn prints_help_with_flag() {
    let mut cmd = Command::cargo_bin("my_cli").unwrap();

    cmd.arg("--help")
        .assert()
        .success()
        .stdout(predicate::str::contains("USAGE"));
}

This integration test runs the compiled binary, passes --help, and checks the output. For CLI-heavy repos, these are some of the best examples of testing in Rust because they mirror exactly what end users experience.


Database and web API examples of testing in Rust

Real services talk to databases and expose HTTP endpoints. Here’s a trimmed-down example of testing a web handler with axum and tower.

## Cargo.toml
[dependencies]
axum = "0.7"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"

[dev-dependencies]
tower = "0.5"
// src/api.rs
use axum::{routing::get, Json, Router};
use serde::Serialize;

#[derive(Serialize)]
struct Health {
    status: String,
}

async fn health_check() -> Json<Health> {
    Json(Health { status: "ok".into() })
}

pub fn app() -> Router {
    Router::new().route("/health", get(health_check))
}

#[cfg(test)]
mod tests {
    use super::*;
    use axum::body::Body;
    use axum::http::{Request, StatusCode};
    use tower::ServiceExt; // for `oneshot`

    #[tokio::test]
    async fn health_endpoint_returns_ok() {
        let app = app();

        let response = app
            .oneshot(Request::builder().uri("/health").body(Body::empty()).unwrap())
            .await
            .unwrap();

        assert_eq!(response.status(), StatusCode::OK);

        let body_bytes = axum::body::to_bytes(response.into_body(), usize::MAX)
            .await
            .unwrap();
        let body_str = String::from_utf8(body_bytes.to_vec()).unwrap();
        assert!(body_str.contains("\"status\":\"ok\""));
    }
}

These are realistic examples of testing in Rust microservices. They exercise routing, serialization, and response codes without requiring a real network port. For database-backed endpoints, teams often spin up ephemeral containers in CI (for example, Postgres in Docker) and point test configuration at them.

If you’re building anything that touches user data or regulated data (healthcare, finance), combining these tests with security guidance from sources like the National Institute of Standards and Technology is a smart move.


Snapshot testing examples of UI-like output

When you generate structured or human-readable output (JSON, Markdown, logs), snapshot testing can save time. In Rust, crates like insta provide a simple workflow.

## Cargo.toml
[dev-dependencies]
insta = { version = "1", features = ["yaml"] }
// src/report.rs
use std::collections::BTreeMap;

pub fn build_report() -> BTreeMap<String, u32> {
    let mut map = BTreeMap::new();
    map.insert("passed".into(), 42);
    map.insert("failed".into(), 3);
    map
}

#[cfg(test)]
mod tests {
    use super::*;
    use insta::assert_yaml_snapshot;

    #[test]
    fn report_format_is_stable() {
        let report = build_report();
        assert_yaml_snapshot!("report_v1", report);
    }
}

First run: cargo insta test writes a snapshot file. Later runs compare output to that snapshot. If you intentionally change the format, you accept the new snapshot. These are subtle but powerful examples of examples of testing in Rust when you care about stable public output formats.


Performance and regression examples of testing in Rust

Rust doesn’t ship a benchmarking harness in the stable test crate anymore, but the community has filled that gap with crates like criterion. While benchmarks are not tests in the strict sense, many teams treat them as a form of regression testing for performance-sensitive code.

## Cargo.toml
[dev-dependencies]
criterion = "0.5"

[[bench]]
name = "sort_bench"
harness = false
// benches/sort_bench.rs
use criterion::{criterion_group, criterion_main, Criterion};

fn sort_large_vec(c: &mut Criterion) {
    c.bench_function("sort 10k ints", |b| {
        b.iter(|| {
            let mut v: Vec<i32> = (0..10_000).rev().collect();
            v.sort();
        })
    });
}

criterion_group!(benches, sort_large_vec);
criterion_main!(benches);

Running cargo bench gives you timing data over multiple runs, catching slowdowns. For performance-sensitive services, these are some of the best examples of testing in Rust behavior over time, especially when combined with CI thresholds or manual review.

If you’re curious about how to interpret performance data statistically, public resources from universities (for example, statistics courses at harvard.edu) are surprisingly relevant even to low-level Rust code.


Organizing tests in 2024–2025 Rust projects

By 2024–2025, common practice in production Rust projects has converged on a few patterns:

  • Keep small unit tests in the same file as the code.
  • Put API-level and CLI tests under tests/ as separate crates.
  • Use async test macros (tokio::test, async_std::test) for async code.
  • Reach for proptest or similar when you’re testing invariants or parsers.
  • Use snapshot testing (insta) for anything with stable, structured output.

If you browse popular crates on crates.io, you’ll see these patterns repeated. Real examples of testing in Rust from those repos are often a better guide than any abstract tutorial.


FAQ: examples of testing in Rust

Q: What are some basic examples of testing in Rust I should start with?
Begin with inline unit tests using #[cfg(test)] mod tests in the same file as your functions. Write tests for both success and error cases, and run them with cargo test. As your crate grows, add integration tests in the tests/ directory that use your crate like an external dependency.

Q: Can you show an example of testing async code without external crates?
On stable Rust, you usually rely on a runtime crate like tokio or async-std for async tests. You can manually create a small executor for very simple cases, but in real examples of testing in Rust services, teams almost always use #[tokio::test] or similar because it matches production behavior.

Q: Do I need property-based tests for every project?
No. Property-based tests shine when you have clear invariants or complex input spaces: parsers, encoders/decoders, protocol logic, or numeric algorithms. For straightforward business logic, targeted unit and integration tests are usually enough, though having one or two proptest-based suites can still catch surprising edge cases.

Q: How do I test code that talks to external services or databases?
Common patterns include:

  • Abstracting external calls behind traits and mocking them in tests.
  • Running real dependencies (like Postgres or Redis) in containers during CI.
  • Using in-memory alternatives where behavior is close enough.
    Most real examples of testing in Rust microservices combine these: mock for unit tests, real containers for integration tests.

Q: Are there best examples of testing in Rust for learning patterns quickly?
Yes. Look at mature crates and frameworks on GitHub: tokio, axum, serde, reqwest, and others. Their test suites provide high-quality examples of examples of testing in Rust across async code, APIs, error handling, and more.

Explore More Rust Code Snippets

Discover more examples and insights in this category.

View All Rust Code Snippets