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:
| Call | Behavior |
|---|---|
Task.Delay | Stays pending until the clock reaches the end of the delay |
PeriodicTimer.WaitForNextTickAsync | Stays pending until the clock reaches the next tick |
Thread.Sleep | Returns immediately without moving the clock |
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.