Trellis.Testing.Worker
3.0.0-alpha.342
dotnet add package Trellis.Testing.Worker --version 3.0.0-alpha.342
NuGet\Install-Package Trellis.Testing.Worker -Version 3.0.0-alpha.342
<PackageReference Include="Trellis.Testing.Worker" Version="3.0.0-alpha.342" />
<PackageVersion Include="Trellis.Testing.Worker" Version="3.0.0-alpha.342" />
<PackageReference Include="Trellis.Testing.Worker" />
paket add Trellis.Testing.Worker --version 3.0.0-alpha.342
#r "nuget: Trellis.Testing.Worker, 3.0.0-alpha.342"
#:package Trellis.Testing.Worker@3.0.0-alpha.342
#addin nuget:?package=Trellis.Testing.Worker&version=3.0.0-alpha.342&prerelease
#tool nuget:?package=Trellis.Testing.Worker&version=3.0.0-alpha.342&prerelease
Trellis.Testing.Worker
Integration-test harness for BackgroundService workers built on Trellis.
Installation
dotnet add package Trellis.Testing.Worker
Quick Example
using Microsoft.Extensions.DependencyInjection;
using Trellis.Authorization;
using Trellis.Mediator;
using Trellis.Testing.Worker;
var systemActor = Actor.Create(
"subscription-renewal-worker",
new HashSet<string>(["Subscriptions.Read", "Subscriptions.Write"]));
await using var harness = await WorkerHarness<SubscriptionRenewalWorker>.CreateAsync(opts =>
{
opts.SystemActor = systemActor;
opts.ConfigureServices(services =>
{
services.AddLogging();
services.AddDomainEventDispatch(); // same registration as production
services.AddSingleton<ISubscriptionRepository, FakeSubscriptionRepository>();
services.AddScoped<IExternalGateway, FakeExternalGateway>();
});
opts.SeedAsync(async (sp, ct) =>
{
var repo = sp.GetRequiredService<ISubscriptionRepository>();
await repo.AddAsync(new Subscription { RenewsAt = opts.InitialTime.AddDays(1) }, ct);
});
});
await harness.StartAsync();
await harness.SettleAsync(); // yield real time so the worker registers its first Task.Delay
harness.Time.Advance(TimeSpan.FromDays(1));
var reminded = await harness.WaitForEventAsync<SubscriptionReminderSent>();
reminded.SubscriptionId.Should().Be(expectedId);
Deterministic alternative to
SettleAsync(): have the worker REGISTER its firstTask.Delay(period, time, ct)(e.g.var nextDelay = Task.Delay(period, time, ct);) BEFORE callingIWorkerTickSignal.SignalAsync("ready", ct), thenawaitthe saved delay. TheTask.Delay(TimeSpan, TimeProvider, CancellationToken)overload eagerly callstimeProvider.CreateTimer(...)when invoked, so the callback is registered withFakeTimeProviderbefore the signal fires —await harness.WaitForTickAsync("ready")can then release and the test can safely callTime.Advance(...)with no race. Signaling beforeTask.Delay(...)would leave a gap during which the test could advance the clock before any callback was registered. No real-time yield, no flakiness.Wiring EF Core with SQLite? Don't pair
AddDbContextFactory<T>withData Source=:memory:— every new connection opens a fresh database, so the seed and the worker see different empty stores. Use a shared/openSqliteConnection(see the integration-testing article) or a temp-file SQLite database.
Key Features
IHostwith a deterministicFakeTimeProvider— advance the clock withharness.Time.Advance(...)to driveTask.Delay(interval, timeProvider, ct)continuations on demand.TestActorProviderregistered as theIActorProvider— gives workers an ambient system actor withoutHttpContext. Override withopts.SystemActor.- Domain-event capture — every event published through Trellis's mediator pipeline is captured. Inspect via
harness.Events<TEvent>(); await one viaharness.WaitForEventAsync<TEvent>(predicate). - Optional tick signal — workers that emit no domain events can resolve
IWorkerTickSignaland callSignalAsync(name)at the end of each tick so the test can block onharness.WaitForTickAsync(name). - Race-proof waits —
WaitForEventAsyncandWaitForTickAsyncsnapshot existing captures before subscribing so events that fire betweenAdvance(...)and the wait still satisfy the wait. - Real-time timeouts — wait timeouts are measured against the real clock, not the fake one;
harness.Time.Advance(...)does not consume the timeout budget.
What the harness does not do
- It does not call
services.AddDomainEventDispatch()— worker tests are integration tests of the production composition root. Register it in yourConfigureServicescallback the same way the worker's production host does. - It does not wire
FakeLogger. AddMicrosoft.Extensions.Diagnostics.Testingandopts.ConfigureLogging(b => b.AddFakeLogging())in your test if you need it.
Documentation
Part of Trellis
This package is part of the Trellis framework.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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. |
-
net10.0
- Microsoft.Extensions.Hosting (>= 10.0.7)
- Microsoft.Extensions.TimeProvider.Testing (>= 10.5.0)
- Trellis.Authorization (>= 3.0.0-alpha.342)
- Trellis.Core (>= 3.0.0-alpha.342)
- Trellis.Mediator (>= 3.0.0-alpha.342)
- Trellis.Testing (>= 3.0.0-alpha.342)
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 |
|---|---|---|
| 3.0.0-alpha.342 | 38 | 6/5/2026 |
| 3.0.0-alpha.337 | 40 | 6/3/2026 |
| 3.0.0-alpha.336 | 40 | 6/3/2026 |