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
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Immediate.Jobs.Testing" Version="0.5.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Immediate.Jobs.Testing" Version="0.5.0" />
                    
Directory.Packages.props
<PackageReference Include="Immediate.Jobs.Testing" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Immediate.Jobs.Testing --version 0.5.0
                    
#r "nuget: Immediate.Jobs.Testing, 0.5.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Immediate.Jobs.Testing@0.5.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Immediate.Jobs.Testing&version=0.5.0
                    
Install as a Cake Addin
#tool nuget:?package=Immediate.Jobs.Testing&version=0.5.0
                    
Install as a Cake Tool

Immediate.Jobs.Testing

NuGet Documentation License

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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.5.0 37 8/28/2026
0.4.0 75 8/12/2026
0.3.0 64 8/7/2026
0.2.0 72 8/4/2026
0.1.0 66 7/31/2026