Test Utilities

Version 0.1.0 Updated Jun 28, 2026

Test helpers are available behind the test-util feature. They are not hidden behind #[cfg(test)], so downstream crates can enable them in their own dev-dependencies.

[dev-dependencies]
monotony = { version = "0.1.0", features = ["test-util"] }

Use FixedMonotonicClock::with_elapsed(...) for code that calls now() exactly twice. Use QueuedMonotonicClock::from_instants(...) when a test needs several pre-seeded instants. Use ManualMonotonicClock::advance(...) for polling loops and timeout code where the test should explicitly move time between observations.

Fixed elapsed time

Use FixedMonotonicClock when the code under test reads the clock once before work starts and once after it finishes.

use std::time::Duration;

use monotony::{MonotonicClock, test_util::FixedMonotonicClock};

fn measure_elapsed(clock: &dyn MonotonicClock) -> Duration {
    let started_at = clock.now();
    clock.now().duration_since(started_at)
}

let clock = FixedMonotonicClock::with_elapsed(Duration::from_millis(250));

assert_eq!(measure_elapsed(&clock), Duration::from_millis(250));

Queued instants

Use QueuedMonotonicClock when the code under test needs a sequence of known clock readings.

use std::time::{Duration, Instant};

use monotony::{MonotonicClock, test_util::QueuedMonotonicClock};

fn collect_ticks(clock: &dyn MonotonicClock, count: usize) -> Vec<Instant> {
    (0..count).map(|_| clock.now()).collect()
}

let first = Instant::now();
let second = first + Duration::from_millis(10);
let third = second + Duration::from_millis(20);
let clock = QueuedMonotonicClock::from_instants([first, second, third]);

assert_eq!(collect_ticks(&clock, 3), vec![first, second, third]);

Manual time

Use ManualMonotonicClock when the test needs to move time between repeated observations, such as timeout or polling code.

use std::time::{Duration, Instant};

use monotony::{MonotonicClock, test_util::ManualMonotonicClock};

fn has_timed_out(clock: &dyn MonotonicClock, started_at: Instant) -> bool {
    clock.now().duration_since(started_at) >= Duration::from_secs(5)
}

let started_at = Instant::now();
let clock = ManualMonotonicClock::new(started_at);

assert!(!has_timed_out(&clock, started_at));

clock.advance(Duration::from_secs(5));

assert!(has_timed_out(&clock, started_at));