Table of Contents

Class ObservableFakeTimeProvider

Namespace
TimeAssertions
Assembly
TimeAssertions.dll

An ObservableTimeProvider over its own Microsoft.Extensions.Time.Testing.FakeTimeProvider: one object to inject into the code under test, to advance, and to assert on. Every ObservableTimeProvider member and assertion applies unchanged, and the advance helpers drive timer-based loops without real time: AdvanceAndSettleAsync(TimeSpan, CancellationToken), AdvanceOnEachTimerUntilAsync(Task, TimeSpan, CancellationToken), and AdvanceUntilAsync(TimeSpan, Func<bool>, TimeSpan, CancellationToken).

public sealed class ObservableFakeTimeProvider : ObservableTimeProvider
Inheritance
ObservableFakeTimeProvider
Inherited Members
Extension Methods

Remarks

Code under test that waits on the injected provider (a Task.Delay(delay, timeProvider, ct), a new CancellationTokenSource(timeout, timeProvider), a WaitAsync(timeout, timeProvider, ct)) creates one timer per wait, often on a background thread. The helpers advance only once such a timer exists, so an advance can never come too early, and they never sleep in real time.

Constructors

ObservableFakeTimeProvider()

Initializes a provider over a new Microsoft.Extensions.Time.Testing.FakeTimeProvider with its default start time.

public ObservableFakeTimeProvider()

ObservableFakeTimeProvider(DateTimeOffset)

Initializes a provider over a new Microsoft.Extensions.Time.Testing.FakeTimeProvider starting at startDateTime.

public ObservableFakeTimeProvider(DateTimeOffset startDateTime)

Parameters

startDateTime DateTimeOffset

The initial date and time of the fake clock.

Properties

Fake

Gets the owned Microsoft.Extensions.Time.Testing.FakeTimeProvider, for its other settings (for example Microsoft.Extensions.Time.Testing.FakeTimeProvider.AutoAdvanceAmount or SetLocalTimeZone(TimeZoneInfo)). Inject this ObservableFakeTimeProvider into the code under test, not the fake itself: timers created directly on the fake are not observed.

public FakeTimeProvider Fake { get; }

Property Value

FakeTimeProvider

Methods

Advance(TimeSpan)

Advances the fake clock by delta, firing every timer that becomes due.

public void Advance(TimeSpan delta)

Parameters

delta TimeSpan

The amount of time to advance.

AdvanceAndSettleAsync(TimeSpan, CancellationToken)

Advances the fake clock by delta and then waits until the loops woken by it have re-armed: for every one-shot timer that fired during the advance, a timer has been armed, either created or re-scheduled with Change(TimeSpan, TimeSpan) (a callback that re-arms its own one-shot timer).

public Task AdvanceAndSettleAsync(TimeSpan delta, CancellationToken cancellationToken)

Parameters

delta TimeSpan

The amount of time to advance.

cancellationToken CancellationToken

The only bound of the wait, typically the test's token.

Returns

Task

A task that completes once the loops woken by the advance have armed their next timers.

Remarks

A one-shot timer that fired is done; a loop that keeps running schedules its next wait by creating a timer with a due time or re-scheduling one with Change(TimeSpan, TimeSpan) (a timer created disabled counts once a change arms it), so "as many armed timers as fired one-shot timers" means every woken loop reached its next wait. Periodic timers keep their schedule and are not waited for; use AdvanceUntilAsync(TimeSpan, Func<bool>, TimeSpan, CancellationToken) for loops driven by a periodic timer.

The counts are those of the whole provider: a timer that other code creates or re-schedules during the wait counts as well, so the settle can return before a woken loop has finished its step. Rely on it when the loops being advanced are the only code arming timers on this provider; otherwise wait for the loop's own signal, for example a WaitUntilAsync(Func<ObservableTimeProvider, bool>, CancellationToken) condition on its state.

A loop that ends after its timer fired arms no new one, so the wait then runs until cancellationToken is canceled. The resulting OperationCanceledException says how many timers fired and how many were armed.

Exceptions

OperationCanceledException

cancellationToken was canceled before the woken loops re-armed.

AdvanceOnEachTimerUntilAsync(Task, TimeSpan, CancellationToken)

Advances the fake clock by step each time the code under test has created a timer, until until completes. Drives a loop through any number of timed waits (for example a reconnect backoff per failed attempt) without real time: it advances only once a timer exists, so no advance is lost.

[SuppressMessage("Usage", "VSTHRD003:Avoid awaiting foreign Tasks", Justification = "Observing the caller's task is the documented contract of this method: it advances until that task completes. Test code runs without a SynchronizationContext or JoinableTaskFactory, so there is no thread to deadlock.")]
public Task AdvanceOnEachTimerUntilAsync(Task until, TimeSpan step, CancellationToken cancellationToken)

Parameters

until Task

The task whose completion ends the advancing, for example a start that returns once connected.

step TimeSpan

The fake time per advance; at least the longest single wait the loop schedules.

cancellationToken CancellationToken

The only bound of the wait, typically the test's token.

Returns

Task

A task that completes once until has completed. It does not observe the outcome of until; await that task afterwards.

Remarks

The first advance happens as soon as any timer has been created through this provider, including one created before the call; after that, each advance waits for a timer created since the previous one.

Exceptions

ArgumentNullException

until is null.

ArgumentOutOfRangeException

step is not positive.

OperationCanceledException

cancellationToken was canceled before until completed.

AdvanceUntilAsync(TimeSpan, Func<bool>, TimeSpan, CancellationToken)

Advances the fake clock in steps of step, settling after each step (see AdvanceAndSettleAsync(TimeSpan, CancellationToken)), until until holds or maxAdvance of fake time has passed. Suits loops driven by a periodic timer, for example "until TimerFireCount reaches 6".

public Task AdvanceUntilAsync(TimeSpan step, Func<bool> until, TimeSpan maxAdvance, CancellationToken cancellationToken)

Parameters

step TimeSpan

The fake time per advance.

until Func<bool>

The condition to reach; checked before each step, on the calling thread.

maxAdvance TimeSpan

The most fake time to advance before giving up; the last step is shortened so the clock never moves past it. A fake-time bound, so the outcome is deterministic.

cancellationToken CancellationToken

Bounds the settle waits, typically the test's token.

Returns

Task

A task that completes once until holds.

Exceptions

ArgumentNullException

until is null.

ArgumentOutOfRangeException

step is not positive, or maxAdvance is negative.

TimeoutException

until did not hold after advancing maxAdvance.

OperationCanceledException

cancellationToken was canceled during a settle wait.

SetUtcNow(DateTimeOffset)

Sets the fake clock to value, firing every timer that becomes due.

public void SetUtcNow(DateTimeOffset value)

Parameters

value DateTimeOffset

The new date and time.