SaaSCore.Testing 0.5.0-preview.4

This is a prerelease version of SaaSCore.Testing.
dotnet add package SaaSCore.Testing --version 0.5.0-preview.4
                    
NuGet\Install-Package SaaSCore.Testing -Version 0.5.0-preview.4
                    
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="SaaSCore.Testing" Version="0.5.0-preview.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="SaaSCore.Testing" Version="0.5.0-preview.4" />
                    
Directory.Packages.props
<PackageReference Include="SaaSCore.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 SaaSCore.Testing --version 0.5.0-preview.4
                    
#r "nuget: SaaSCore.Testing, 0.5.0-preview.4"
                    
#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 SaaSCore.Testing@0.5.0-preview.4
                    
#: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=SaaSCore.Testing&version=0.5.0-preview.4&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=SaaSCore.Testing&version=0.5.0-preview.4&prerelease
                    
Install as a Cake Tool

SaaSCore.Testing

SaaSCore.Testing provides a lightweight set of helpers, fixtures, and utilities to support writing fast, reliable, and repeatable tests across the SaaSCore ecosystem.
It is designed to remove boilerplate when testing database interactions, specifications, and application-level components --- while remaining completely optional and unobtrusive.

This package is used internally by SaaSCore and SaaSCore.* modules but can also be referenced by consuming applications.


✨ Features

  • API regression harness
    Starts an isolated ASP.NET Core API with WebApplicationFactory<TEntryPoint>, per-scenario configuration, service replacement, test authentication, scoped seeding/resetting, outbound HTTP stubs, and captured logs for diagnostics.

  • SaaSCore EF Core test contexts
    Provides preconfigured in-memory and SQLite-backed SaaSCoreDbContext factories for validating repository queries, specifications, interceptors, and tenant-aware persistence logic.

  • Automatic test database bootstrapping
    Creates and seeds a fresh database instance per test (or per test class), ensuring test isolation.

  • Extension points for custom seeding
    Easily inject your own seed data for database tests and API regression scenarios.

  • Failure simulation
    Includes EF Core interceptors for deliberately failing queries or saves so error paths can be tested without brittle mocks.


📦 Installation

This package is internal for now. Once extracted into its own NuGet package, it will be installed via:

dotnet add package SaaSCore.Testing

Until then, reference the project from your solution:

<ItemGroup>
  <ProjectReference Include="..\SaaSCore.Testing\SaaSCore.Testing.csproj" />
</ItemGroup>

🚀 Getting Started

1. Create an isolated API regression harness

Add a public partial Program type to the API project under test if it uses top-level statements:

public partial class Program;

Then create a harness per test or per Reqnroll scenario:

await using var harness = await RegressionHarness
    .ForApi<Program>()
    .WithEnvironment("Regression")
    .WithConfiguration("FeatureFlags:UseFakePayments", "true")
    .WithServices(services =>
    {
        services.ReplaceScoped<IMyDependency, FakeMyDependency>();
    })
    .WithTestAuthentication(user => user
        .WithSubject("test-user")
        .WithClaim("tenant_id", "tenant-001")
        .WithRole("admin"))
    .BuildAsync();

var response = await harness.Api.PostAsJsonAsync("/orders", request);

The harness exposes:

  • harness.Api for API-focused HTTP calls and diagnostic success assertions.
  • harness.Services, CreateScope(), and CreateAsyncScope() for assertions against application services.
  • WithSeeder(...), WithScopedSeeder(...), WithReset(...), and ResetAsync() for scenario-level setup and cleanup.
  • harness.Logs for captured application logs.

2. Stub outbound HTTP calls

For services registered with IHttpClientFactory, replace named clients with deterministic local handlers:

await using var harness = await RegressionHarness
    .ForApi<Program>()
    .WithHttpClientStub("payments", stub =>
    {
        stub.When(HttpMethod.Post, "/charges")
            .RespondJson(new { id = "ch_test_123", status = "approved" });
    })
    .BuildAsync();

var payments = harness.GetHttpClientStub("payments");
Assert.Single(payments.Interactions);

If a response is expected to be successful, use the diagnostic helper:

await harness.Api.GetAndEnsureSuccessAsync("/health");

On failure, RegressionApiRequestException includes the request, status code, response body, and recent captured warning/error logs.

3. Use with Reqnroll

SaaSCore.Testing does not force a Reqnroll dependency on every consumer. The package provides a framework-agnostic RegressionScenarioContext<TEntryPoint> that can be registered in Reqnroll's scenario container:

[Binding]
public sealed class RegressionHooks
{
    private readonly RegressionScenarioContext<Program> scenario;

    public RegressionHooks(RegressionScenarioContext<Program> scenario)
    {
        this.scenario = scenario;
    }

    [BeforeScenario]
    public Task BeforeScenario()
        => scenario
            .Configure(builder => builder
                .WithEnvironment("Regression")
                .WithConfiguration("FeatureFlags:UseFakePayments", "true"))
            .StartAsync();

    [AfterScenario]
    public async Task AfterScenario()
    {
        await scenario.DisposeAsync();
    }
}

[Binding]
public sealed class OrderSteps
{
    private readonly RegressionScenarioContext<Program> scenario;

    public OrderSteps(RegressionScenarioContext<Program> scenario)
    {
        this.scenario = scenario;
    }

    [When("I create an order")]
    public async Task WhenICreateAnOrder()
    {
        await scenario.Api.PostAsJsonAsync("/orders", new CreateOrderRequest());
    }
}

Register RegressionScenarioContext<Program> as a scenario-scoped dependency in the Reqnroll project. Each scenario gets its own harness, client, service provider, logs, stubs, and reset lifecycle.


4. Use the SaaSCore database factories

var tenantContext = TenantContextFactory.Create();
await using var context = SaaSCoreDbContextTestFactory.CreateInMemory(tenantContext);

For relational behavior such as constraints, transactions, or command interceptors, use the SQLite-backed factory:

await using var context = SaaSCoreDbContextTestFactory.CreateSqliteInMemory(tenantContext);

5. Seed your test data

var data = new TestDataBuilder<SaaSCoreDbContext>(context);
data.Add(entity);
await data.SaveAsync();

🧰 Included Utilities


Utility Description


RegressionHarness Fluent entry point for isolated API regression tests.

RegressionScenarioContext Scenario-scoped harness wrapper for Reqnroll and other BDD runners.

HttpClientStub Lightweight outbound HTTP simulation for named HttpClient dependencies.

SaaSCoreDbContextTestFactory Creates in-memory and SQLite-backed SaaSCore DbContext instances.

TenantContextFactory Creates tenant contexts for tenant-aware tests.

TestDataBuilder Small helper for adding and saving test entities.

ThrowOnCommandInterceptor Simulates query/command failures.

ThrowOnSaveChangesInterceptor Simulates persistence failures.


📐 Design Principles

SaaSCore.Testing follows the core SaaSCore philosophy:

  • No mocking what you can prove --- prefer real EF Core behaviour over mocked abstractions.
  • Realistic data, minimal ceremony --- seed helpers give structure without forcing test complexity.
  • Composable, not prescriptive --- all utilities can be replaced or extended.

🗺 Roadmap

  • Snapshot testing helpers.
  • Optional package-level Reqnroll bindings if consumers want a direct Reqnroll integration package later.
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 was computed.  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 was computed.  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. 
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-preview.4 0 5/14/2026
0.5.0-preview.3 0 5/14/2026
0.5.0-preview.2 64 3/29/2026
0.5.0-preview.1 60 3/8/2026
0.4.0-preview.1 61 2/9/2026
0.3.0-preview.3 64 1/11/2026
0.3.0-preview.2 68 1/5/2026
0.3.0-preview.1 71 1/5/2026
0.2.0-preview.15 121 12/14/2025
0.2.0-preview.14 115 12/14/2025
0.2.0-preview.13 112 12/14/2025
0.2.0-preview.12 86 12/12/2025
0.2.0-preview.11 187 12/11/2025
0.2.0-preview.10 384 12/11/2025
0.2.0-preview.9 384 12/11/2025
0.2.0-preview.8 383 12/11/2025
0.2.0-preview.7 381 12/11/2025
0.2.0-preview.6 372 12/11/2025
0.2.0-preview.5 378 12/11/2025
0.2.0-preview.4 383 12/11/2025
Loading failed