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
startDateTimeDateTimeOffsetThe 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
deltaTimeSpanThe 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
deltaTimeSpanThe amount of time to advance.
cancellationTokenCancellationTokenThe 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
cancellationTokenwas 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
untilTaskThe task whose completion ends the advancing, for example a start that returns once connected.
stepTimeSpanThe fake time per advance; at least the longest single wait the loop schedules.
cancellationTokenCancellationTokenThe only bound of the wait, typically the test's token.
Returns
- Task
A task that completes once
untilhas completed. It does not observe the outcome ofuntil; 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
untilis null.- ArgumentOutOfRangeException
stepis not positive.- OperationCanceledException
cancellationTokenwas canceled beforeuntilcompleted.
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
stepTimeSpanThe fake time per advance.
untilFunc<bool>The condition to reach; checked before each step, on the calling thread.
maxAdvanceTimeSpanThe 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.
cancellationTokenCancellationTokenBounds the settle waits, typically the test's token.
Returns
- Task
A task that completes once
untilholds.
Exceptions
- ArgumentNullException
untilis null.- ArgumentOutOfRangeException
stepis not positive, ormaxAdvanceis negative.- TimeoutException
untildid not hold after advancingmaxAdvance.- OperationCanceledException
cancellationTokenwas 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
valueDateTimeOffsetThe new date and time.