Skip to main content

Auto-advance

By default, MockTimeSystem advances its clock every time the code under test waits. A call to Thread.Sleep(5s) or Task.Delay(5s) returns immediately and the next read of DateTime.Now reflects 5 seconds later. This is the right default: most tests want to skip the wait, not enforce it.

MockTimeSystem timeSystem = new(new DateTime(2026, 1, 1, 0, 0, 0, DateTimeKind.Utc));

await timeSystem.Task.Delay(TimeSpan.FromMinutes(10));

await That(timeSystem.DateTime.UtcNow)
.IsEqualTo(new DateTime(2026, 1, 1, 0, 10, 0, DateTimeKind.Utc));

Disabling auto-advance​

When you need to assert that code waited (instead of just letting it through), turn auto-advance off via MockTimeSystemOptions.DisableAutoAdvance() and move the clock yourself with TimeProvider.AdvanceBy(...) or TimeProvider.SetTo(...):

MockTimeSystem timeSystem = new(o => o.DisableAutoAdvance());

Task delay = timeSystem.Task.Delay(TimeSpan.FromMinutes(10));
await That(delay.IsCompleted).IsFalse();

timeSystem.TimeProvider.AdvanceBy(TimeSpan.FromMinutes(10));
await delay; // completes, because the clock has reached the end of the delay

With auto-advance off:

CallBehavior
Task.DelayStays pending until the clock reaches the end of the delay
PeriodicTimer.WaitForNextTickAsyncStays pending until the clock reaches the next tick
Thread.SleepReturns immediately without moving the clock
Awaiting a delay with auto-advance off

Awaiting Task.Delay before anything advances the clock waits forever. Start the delay, advance the clock (or let another task do it), then await it.

Combine this with the notifications hooks to assert what your code asked for.

Multi-threaded scenarios​

All threads share one simulated clock, so two parallel Sleep(5s) calls move it by 10 seconds total, which can be surprising. If your test exercises real parallelism, swap in the thread-aware provider so each async context has its own clock.