Immediate.Jobs.Testing
0.5.0
dotnet add package Immediate.Jobs.Testing --version 0.5.0
NuGet\Install-Package Immediate.Jobs.Testing -Version 0.5.0
<PackageReference Include="Immediate.Jobs.Testing" Version="0.5.0" />
<PackageVersion Include="Immediate.Jobs.Testing" Version="0.5.0" />
<PackageReference Include="Immediate.Jobs.Testing" />
paket add Immediate.Jobs.Testing --version 0.5.0
#r "nuget: Immediate.Jobs.Testing, 0.5.0"
#:package Immediate.Jobs.Testing@0.5.0
#addin nuget:?package=Immediate.Jobs.Testing&version=0.5.0
#tool nuget:?package=Immediate.Jobs.Testing&version=0.5.0
Immediate.Jobs.Testing
Deterministic testing tools for Immediate.Jobs: a harness with fake time, advance-and-drain helpers, capturing in-memory storage, enqueue assertions, a single-job handler-pipeline runner, and storage-provider conformance tests.
Installation
dotnet add package Immediate.Jobs --prerelease
dotnet add package Immediate.Jobs.Testing --prerelease
Deterministic job tests
JobTestHarness hosts the production scheduling service with in-memory storage and a controllable clock, without
starting background threads. Register the generated jobs, handlers, and their dependencies in its service collection:
await using var harness = new JobTestHarness(services =>
{
services.AddMyAppHandlers();
services.AddMyAppJobs();
services.AddSingleton<IEmailSender, RecordingEmailSender>();
});
await using var scope = harness.Services.CreateAsyncScope();
var scheduler = scope.ServiceProvider.GetRequiredService<SendWelcomeEmail.Scheduler>();
var handle = await scheduler.ScheduleAsync(
new(userId, "v2"),
TimeSpan.FromMinutes(10),
cancellationToken
);
var enqueued = await harness.AssertEnqueuedAsync<SendWelcomeEmail.Payload>(
handle,
JobState.Scheduled,
cancellationToken
);
Assert.Equal(userId, enqueued.Payload.UserId);
await harness.AdvanceTimeAndDrainAsync(TimeSpan.FromMinutes(10), cancellationToken);
Assert.Equal(JobState.Succeeded, (await harness.GetJobAsync(handle, cancellationToken)).State);
Delayed work, scheduled occurrences, timeouts, and backoff tests do not need wall-clock sleeps. The harness also exposes
persisted-job queries and focused assertions for batches, continuations, and dependency cascades. Register generated
jobs in the callback, but do not call ConfigureStorage; the harness installs its own in-memory provider and fake clock.
Capturing scheduler calls
JobTestHarness installs CapturingJobStorage behind the production schedulers. Calls are recorded without preventing
jobs from being queried, cancelled, or executed normally:
await using var harness = new JobTestHarness(services => services.AddMyAppJobs());
var scheduler = harness.Services.GetRequiredService<SendWelcomeEmail.Scheduler>();
var payload = new SendWelcomeEmail.Payload(userId, "v2");
var handle = await scheduler.EnqueueAsync(
payload,
groupId: "tenant-a",
cancellationToken: cancellationToken
);
var captured = harness.Captures.FindJob(handle)!;
Assert.Equal(handle, captured.JobHandle);
Assert.Equal("tenant-a", captured.GroupId);
await scheduler.CancelAsync(handle, cancellationToken);
Assert.Equal(JobState.Cancelled, (await harness.GetJobAsync(handle, cancellationToken)).State);
The same CapturingJobStorage instance is available from harness.Captures and dependency injection. Its snapshots
preserve call order for jobs, continuations, batches, dynamic batch additions, recurring definitions, and recurring
materializations. Clear() resets only the capture log; it does not remove persisted jobs.
Use Jobs, Continuations, Batches, BatchJobs, DynamicContinuations, RecurringSchedules,
RecurringOperations, and RecurringMaterializations when a test needs the complete call history rather than one job.
Each property returns a snapshot, so assertions do not observe a collection changing underneath them.
Storage-provider conformance
If you are implementing a new IJobStorage provider, use JobStorageConformanceSuite to verify its shared behavior.
Select the feature flags the provider supports, create a fresh service provider and backend for each case, and pass the
service provider to RunAsync.
private const StorageCapabilities Capabilities =
StorageCapabilities.Queue | StorageCapabilities.Recurring;
public static TheoryData<JobStorageConformanceTestCase> Cases =>
[.. JobStorageConformanceSuite.GetCases(Capabilities)];
[Theory]
[MemberData(nameof(Cases))]
public async Task StorageConforms(JobStorageConformanceTestCase testCase)
{
await using var services = await AcmeStorageFixture.CreateServiceProviderAsync();
await testCase.RunAsync(services);
}
The fixture should use the provider's normal public registration method, register a FakeTimeProvider as
TimeProvider, and isolate its database, schema, or key prefix. See the
storage-provider testing documentation
for isolation requirements and capability selection.
More information
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. net11.0 is compatible. |
-
net10.0
- Microsoft.Extensions.DependencyInjection (>= 10.0.11)
- Microsoft.Extensions.TimeProvider.Testing (>= 10.9.0)
-
net11.0
- Microsoft.Extensions.DependencyInjection (>= 11.0.0-preview.7.26381.103)
- Microsoft.Extensions.TimeProvider.Testing (>= 10.9.0)
-
net8.0
- Microsoft.Extensions.DependencyInjection (>= 8.0.1)
- Microsoft.Extensions.TimeProvider.Testing (>= 8.10.0)
-
net9.0
- Microsoft.Extensions.DependencyInjection (>= 9.0.19)
- Microsoft.Extensions.TimeProvider.Testing (>= 9.10.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.