MartinDrozdik.DDD.Testing 0.7.1.1

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

DDD Testing Library

NuGet NuGet Downloads Build & Test .NET License

Common test tooling for the DDD libraries. Provides test fixtures, utilities, and helpers to make testing your DDD applications easier and more consistent. Check the demo tests for examples of how to use it in real tests.

Installation

dotnet add package xunit.v3
dotnet add package MartinDrozdik.DDD.Testing

Philosophy

  • Write tests, not test infrastructure - Stop copy-pasting the same WebApplicationFactory boilerplate across every project.
  • Integration tests, not unit tests - Test the whole stack with real dependencies – reveals much more bugs. Unit tests still valuable tho.
  • Composition over inheritance – Avoid the giant base test class pitfall.
  • Consistent with the rest of the DDD stack - Same pragmatic approach, same "use what makes sense" attitude.
  • xUnit - It has more stars than NUnit lmao.

You still have to write your own tests. But at least you don't have to write the boring parts.

Quick Start

Spin up your app in memory, make requests, assert things. Zero extra ceremony:

// 1. Subclass the builder for your Program.cs (once, in your test project)
public class MyAppBuilder(ITestOutputHelper output) : TestedAppBuilder<Program>(output)
{
    MyAppBuilder(ITestOutputHelper output) : base(output)
    {
        // Add more configuration here
        // Or leave it empty. Nobody's judging.
    }
}

// 2. Use it in your tests
public class MyTests(ITestOutputHelper output) : IDisposable
{
    private readonly TestedApp<Program> _app = new MyAppBuilder(output).Build();

    // Or set specific extra config for this test class
    private readonly TestedApp<Program> _app = new MyAppBuilder(output)
        .WithOption<TestOptions>(e => e.SomeString, value)
        .WithServices(services => services.AddAppOptions<TestOptions>())
        .Build();

    [Fact]
    public async Task Something_works()
    {
        var client = _app.CreateClient();
        var response = await client.GetAsync("/something");
        response.EnsureSuccessStatusCode();
    }

    [Fact]
    public async Task Something_other_works()
    {
        // Or use the builder directly here
        var app = new MyAppBuilder(output).Build();
        var client = app.CreateClient();
        var response = await client.GetAsync("/something");
        response.EnsureSuccessStatusCode();
    }

    public void Dispose() => _app.Dispose();
}

TestedApp & TestedAppBuilder

The TestedApp<TProgram> wraps WebApplicationFactory<TProgram> (yes, the standard one) and adds the things you always end up adding yourself anyway:

  • xUnit log output – Your logs actually show up in the test runner. revoLuTiOnAry.
    • You would be surprised how many people don't do this – and then wonder why they have no logs when their tests fail.
  • Test endpoint injection – Register extra endpoints at test time without touching your production app.
  • Config and options overrides – Change settings for tests without affecting production defaults.
  • Disposable tracking – Attach anything that needs cleanup and it gets disposed with the factory.
  • Mode minor goodies

Build it with the fluent TestedAppBuilder<TProgram>:

var app = new MyAppBuilder(output)
    .WithConfig(builder => builder.UseSetting("SomeSetting", "SomeValue"))
    .WithOption<DatabaseOptions>(o => o.ConnectionString, "Data Source=:memory:")
    .WithServices(services => services.AddSingleton<IMyService, MockMyService>())
    .WithEndpoints(endpoints => endpoints.MapGet("/test-only-route", () => "hello"))
    .WithDisposable(() => Console.WriteLine("cleaned up, congrats"))
    .WithEnvironment(AppEnvironments.Testing)
    .WithUserAndRoles("testuser", ["Admin", "User"])
    .WithClaimsPrincipal(...)
    .Build();

Each With* call stacks – multiple configs, multiple endpoints, multiple disposables, all applied in order. Readable. Composable. Not a pyramid of constructors.

Call Dispose() when you're done.

Testing environment

By default, the tests run in the "Testing" environment. You can change that via the .WithEnvironment("Development") builder method.

This is to strictly separate your test configuration from your development configuration. You can have different appsettings files, different DI registrations, etc., for "Testing" vs "Development".

Use the AppEnvironments.Testing constant or the classic app.Environment.IsTesting() to check if you're running in the Testing environment.

Smoke Tests

Free tests that verify the basics. Because "it starts and doesn't explode" is a valid and surprisingly often-failing test.

Verify the app starts and is healthy:

public class MyAppSmokeTests(ITestOutputHelper output)
    : WebApplicationSmokeTests<Program>(new MyAppBuilder(output))
{
}

Verifies that your OpenAPI document is valid JSON or YAML:

public class MyOpenApiSmokeTests(ITestOutputHelper output)
    : OpenApiSmokeTests<Program>(new MyAppBuilder(output))
{
    protected override IEnumerable<OpenApiEndpoint> GetOpenApiEndpoints() =>
    [
        new OpenApiEndpoint("/openapi/v1.json", OpenApiType.Json),
        new OpenApiEndpoint("/openapi/v1.yaml", OpenApiType.Yaml),
    ];
}

Tests your error handling is wired up correctly:

public class MyAppErrorHandlingTests(ITestOutputHelper output)
    : ErrorHandlingTests<Program>(new MyAppBuilder(output))
{
}

EF Core Context Tests

Tests that your EF Core mappings actually work against a real database. Because "the migration ran" does not mean "the query works":

public class MyDbContextTests(ITestOutputHelper testOutputHelper) : SqlDbContextIntegrationTests<MyDbContext>, IDisposable
{
    private readonly TestedApp<Program> _factory =
        new DemoAppBuilder(testOutputHelper).Build();

    public void Dispose()
    {
        _factory.Dispose();
    }

    protected override MyDbContext GetContext()
    {
        return _factory.GetScopedService<MyDbContext>();
    }
}

Assertions

EqualityAssert

Testing equality implementations is tedious and it's easy to miss edge cases. EqualityAssert covers IEquatable<T>, IEqualityComparer<T>, and equality operators (==, !=) in one shot:

[Fact]
public void InvoiceNumber_equality_is_correct()
{
    var a = InvoiceNumber.Create(2024, 1);
    var b = InvoiceNumber.Create(2024, 1); // same value, different instance
    var c = InvoiceNumber.Create(2024, 2); // different value

    EqualityAssert.TestAllEqualityBehaviors(a, b, c);
}

Or test just the parts you care about:

EqualityAssert.TestEquatable(a, b, c);           // IEquatable<T>
EqualityAssert.TestEqualityComparer(a, b, c);    // IEqualityComparer<T>  
EqualityAssert.TestEqualityOperators(a, b, c);   // == and != operators

Covers symmetry, null/default comparisons, and hash code consistency. Basically everything you'd forget to test manually.

ResultAssert

If you're using Result<T, E> or UnitResult<E> from CSharpFunctionalExtensions, these extension methods give you readable assertions:

[Fact]
public void CreateInvoice_returns_success()
{
    var result = Invoice.Create(InvoiceNumber.Create(2024, 1));
    result.IsSuccess();
}

Demo Tests

The demo test project shows all of this wired together with a real app. Check:

Product 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. 
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.7.1.1 91 5/24/2026
0.7.1 91 5/17/2026
0.7.0 92 5/16/2026
0.6.0 100 5/2/2026
0.5.3.2 99 4/21/2026
0.5.3.1 93 4/21/2026
0.5.3 96 4/19/2026
0.5.1 113 4/10/2026
0.5.0 102 4/6/2026
0.1.1 101 3/21/2026
0.1.0 101 3/21/2026