Spensara Spensara Knowledge Base & Documentation Repository

Repository Docs & Knowledge Base

Consolidated Spensara documentation repository (722 Markdown & architecture documents in ../repository)
Built Word Documents (.docx): Spensara Overview (.docx) Capability Assessment (.docx) Brink POS Ingestion Analysis (.docx) The Borg Ingestion Architecture (.docx)

Agent Tooling (71)

Automation workflows, orchestration references, and developer tooling guides.
agent-tooling/.agents/skills/tunit-testing/references/aspnetcore-integration.md 4,105 bytes · Updated Oct 23, 2026 10:44 AM EDT
Raw File

ASP.NET Core Integration

Use these patterns for ASP.NET Core integration tests built on TUnit.AspNetCore.

Prefer TUnit's ASP.NET Base Types

  • Derive factories from TestWebApplicationFactory<TEntryPoint>, not directly from WebApplicationFactory<TEntryPoint>.
  • Derive test bases from WebApplicationTest<TFactory, TEntryPoint>.
  • This preserves TUnit tracing, per-test logging correlation, and test context propagation.
csharp
public sealed class AppFactory : TestWebApplicationFactory<Program>
{
}

public abstract class TestsBase : WebApplicationTest<AppFactory, Program>
{
}

Factory vs Test Responsibilities

Use the factory for shared defaults that apply to every test in the class/session:

  • shared environment selection
  • shared service replacement defaults
  • shared startup-time configuration defaults

Use the WebApplicationTest overrides for per-test behavior:

  • SetupAsync() for async preparation before factory creation
  • ConfigureTestConfiguration(...) for per-test configuration overrides
  • ConfigureTestServices(...) for per-test DI overrides
  • ConfigureWebHostBuilder(...) only as an escape hatch

Configuration Timing Matters

If configuration must be visible while Program.cs is building the app, put it in:

  • TestWebApplicationFactory.ConfigureStartupConfiguration(...)

Do not rely on ConfigureWebHost(...).ConfigureAppConfiguration(...) for settings that must exist during application startup. That path is too late for some startup reads.

csharp
public sealed class AppFactory : TestWebApplicationFactory<Program>
{
    protected override void ConfigureStartupConfiguration(IConfigurationBuilder configurationBuilder)
    {
        configurationBuilder.AddInMemoryCollection(new Dictionary<string, string?>
        {
            ["Feature:Enabled"] = bool.TrueString,
        });
    }
}

For per-test values discovered in SetupAsync(), use ConfigureTestConfiguration(...):

csharp
public abstract class TestsBase : WebApplicationTest<AppFactory, Program>
{
    protected string SchemaName { get; private set; } = null!;

    protected override async Task SetupAsync()
    {
        SchemaName = GetIsolatedName("schema");
        await CreateSchemaAsync(SchemaName);
    }

    protected override void ConfigureTestConfiguration(IConfigurationBuilder config)
    {
        config.AddInMemoryCollection(new Dictionary<string, string?>
        {
            ["Database:Schema"] = SchemaName,
        });
    }
}

Per-Test Isolation

For shared mutable resources, isolate by test.

  • use GetIsolatedName("...") for tables, schemas, queues, topics
  • use GetIsolatedPrefix() for cache keys, blob prefixes, Redis keys

For EF Core schema isolation, prefer:

  • SchemaName = GetIsolatedName("schema")
  • creating the schema in SetupAsync()
  • IModelCacheKeyFactory keyed by schema
  • dropping the schema in [After(Test)]

Using the Factory in Tests

Factory is a per-test TracedWebApplicationFactory<TEntryPoint>.

Use:

  • Factory.CreateClient() for normal requests
  • Factory.Services for resolving services scoped to the isolated test factory

If you need advanced WebApplicationFactory APIs such as WithWebHostBuilder(...), go through Factory.Inner:

csharp
await using var customFactory = new TracedWebApplicationFactory<Program>(
    Factory.Inner.WithWebHostBuilder(builder =>
    {
        builder.UseSetting("Feature:Enabled", bool.FalseString);
    }));

var client = customFactory.CreateClient();

Service Replacement

When overriding app services in tests, remove or replace existing registrations instead of stacking duplicates.

csharp
protected override void ConfigureTestServices(IServiceCollection services)
{
    services.ReplaceService<IEmailSender>(new FakeEmailSender());
}

Cancellation

Prefer injecting CancellationToken into test methods and hooks.

For code inside WebApplicationTest, use the current test execution token if needed:

csharp
protected CancellationToken CancellationToken => TestContext.Current!.Execution.CancellationToken;