Class HasNoActiveTimersEventuallyAssertion
- Namespace
- TimeAssertions.TUnit
- Assembly
- TimeAssertions.TUnit.dll
TUnit assertion that polls an ObservableTimeProvider in real time until no timer
remains active, or a timeout elapses. Generates the
HasNoActiveTimersEventually(TimeSpan, ...) chain extension via TUnit's
TUnit.Assertions.Attributes.AssertionExtensionAttribute source generator.
[AssertionExtension("HasNoActiveTimersEventually")]
public sealed class HasNoActiveTimersEventuallyAssertion : Assertion<ObservableTimeProvider>, IAssertion
- Inheritance
-
Assertion<ObservableTimeProvider>HasNoActiveTimersEventuallyAssertion
- Implements
-
IAssertion
- Inherited Members
-
Assertion<ObservableTimeProvider>.AssertAsync()Assertion<ObservableTimeProvider>.GetAwaiter()Assertion<ObservableTimeProvider>.AndAssertion<ObservableTimeProvider>.Or
Remarks
Why a real-time poll rather than fake-time advance. A BackgroundService /
IHostedService commonly disposes its timer on a continuation that runs after
StopAsync returns to the caller. The disposal happens on a real asynchronous
continuation, not on a fake-clock tick, so advancing fake time would not surface it. This
assertion therefore polls the live ActiveTimerCount against
a wall-clock deadline, giving the pending disposal continuation time to run.
The condition is checked once before the first delay, so a provider that is already clean passes
without waiting. On timeout the failure message names each surviving timer by the schedule it
carries ([dueTime=..., period=...]), the same shape as the synchronous
HasNoActiveTimers() check.
Cancellation. When the supplied CancellationToken is canceled the poll loop throws OperationCanceledException (a TaskCanceledException from the underlying Delay(TimeSpan, CancellationToken)); the test is recorded as canceled rather than failed.
await host.StopAsync();
await Assert.That(time).HasNoActiveTimersEventually(TimeSpan.FromSeconds(2));
Constructors
HasNoActiveTimersEventuallyAssertion(AssertionContext<ObservableTimeProvider>, TimeSpan, TimeSpan?, CancellationToken)
Initializes the assertion with a polling timeout, poll interval, and cancellation token. Called by the TUnit source generator.
public HasNoActiveTimersEventuallyAssertion(AssertionContext<ObservableTimeProvider> context, TimeSpan timeout, TimeSpan? pollingInterval = null, CancellationToken cancellationToken = default)
Parameters
contextAssertionContext<ObservableTimeProvider>The assertion context supplied by TUnit.
timeoutTimeSpanThe maximum wall-clock time to poll for the active-timer count to reach zero. Must be non-negative.
pollingIntervalTimeSpan?The delay between polls. When null a default of TimeAssertions.TUnit.PollingDefaults.PollingInterval is used. Must be positive when supplied.
cancellationTokenCancellationTokenA token that cancels the poll loop.
Exceptions
- ArgumentOutOfRangeException
timeoutis negative, orpollingIntervalis supplied and not positive.
Methods
CheckAsync(EvaluationMetadata<ObservableTimeProvider>)
Implements the specific check logic for this assertion. Called after the context has been evaluated. Override this method if your assertion uses the default AssertAsync() flow. If you override AssertAsync() with custom logic (like AndAssertion/OrAssertion), you don't need to implement this.
protected override Task<AssertionResult> CheckAsync(EvaluationMetadata<ObservableTimeProvider> metadata)
Parameters
metadataEvaluationMetadata<ObservableTimeProvider>Metadata about the evaluation including value, exception, and timing information
Returns
- Task<AssertionResult>
The result of the assertion check
GetExpectation()
Gets a human-readable description of what this assertion expects. Used in error messages.
protected override string GetExpectation()