Rust Tokio Testing
`#[tokio::test]` is an attribute that runs an async test on a fresh runtime. Tokio timers in a test can run on a paused clock.
#[tokio::test] makes a test async
The attribute turns an async test fn into a normal test: it builds a runtime and block_on's the body:
#[tokio::test]
async fn it_adds() {
assert_eq!(2 + 2, 4);
}Need the multi-thread shape?
Ask for it in the attribute, with the same flavour spelling as the runtime Builder:
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn it_spawns() {
let handle = tokio::spawn(async { 40 + 2 });
assert_eq!(handle.await.unwrap(), 42);
}pause() freezes the clock
tokio::time::pause() freezes the async clock. A sleep of a whole hour then completes almost instantly, once no other work is pending. And it still measures the full hour:
#[tokio::test]
async fn an_hour_passes_fast() {
tokio::time::pause();
let start = Instant::now();
sleep(Duration::from_secs(3600)).await;
assert!(start.elapsed() >= Duration::from_secs(3600));
}advance() steps the clock by hand
advance(duration) moves a paused clock forward by hand, step by step:
#[tokio::test]
async fn step_the_clock() {
tokio::time::pause();
let start = Instant::now();
tokio::time::advance(Duration::from_secs(30)).await;
assert_eq!(start.elapsed(), Duration::from_secs(30));
}Example
// Cargo.toml: tokio = { version = "1", features = ["full", "test-util"] }
use tokio::time::{sleep, Duration, Instant};
#[tokio::main(flavor = "current_thread")]
async fn main() {
// In a real project, this body sits in a #[tokio::test] fn instead of main.
tokio::time::pause();
let start = Instant::now();
sleep(Duration::from_secs(3600)).await;
println!("slept for {:?}", start.elapsed());
}Key points
- Each test gets its own current-thread runtime by default, so tests stay independent
- Pausing affects only Tokio's timers.
In this example, pause() freezes Tokio's clock before the sleep begins. The sleep asks for a whole hour. But with nothing else to do, the runtime jumps the clock straight to the wake-up time. The printed elapsed time is the full hour, yet the program finishes in a blink. In a test, #[tokio::test] would replace #[tokio::main] on the function.
Note
std::time and real I/O still live in the real world.
Try it Yourself
Edit the code, then press Run.
Running is simulated ยท Rust Playground
Exercise
What does tokio::time::pause() do in a test?