Creomobile.Testing.Postgres.Xunit 0.2.3

There is a newer version of this package available.
See the version list below for details.
dotnet add package Creomobile.Testing.Postgres.Xunit --version 0.2.3
                    
NuGet\Install-Package Creomobile.Testing.Postgres.Xunit -Version 0.2.3
                    
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="Creomobile.Testing.Postgres.Xunit" Version="0.2.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Creomobile.Testing.Postgres.Xunit" Version="0.2.3" />
                    
Directory.Packages.props
<PackageReference Include="Creomobile.Testing.Postgres.Xunit" />
                    
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 Creomobile.Testing.Postgres.Xunit --version 0.2.3
                    
#r "nuget: Creomobile.Testing.Postgres.Xunit, 0.2.3"
                    
#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 Creomobile.Testing.Postgres.Xunit@0.2.3
                    
#: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=Creomobile.Testing.Postgres.Xunit&version=0.2.3
                    
Install as a Cake Addin
#tool nuget:?package=Creomobile.Testing.Postgres.Xunit&version=0.2.3
                    
Install as a Cake Tool

Creomobile.Testing.Postgres.Xunit

A PostgreSQL container for xunit integration tests, started once per test assembly via Testcontainers, plus a helper that points its connection string at a database of your choosing.

Usage

Derive from PostgresFixture to declare the image your tests run against, and register that type once per test assembly — an assembly-level attribute applies only to the assembly it is compiled into, so the package cannot do this for you:

using Creomobile.Testing.Postgres;
using Xunit.Sdk;

[assembly: AssemblyFixture(typeof(PostgresAssemblyFixture))]

public sealed class PostgresAssemblyFixture() : PostgresFixture(
    "postgres:18.4@sha256:<the digest of the image your production runs>");

Then take your fixture type as a constructor parameter in any test class:

using Microsoft.EntityFrameworkCore;
using Xunit;

public sealed class CustomerTests(PostgresAssemblyFixture postgresFixture)
{
    const string Database = "customer_tests";

    [Fact]
    public async Task StoresACustomer()
    {
        await using var context = new AppDbContext(
            new DbContextOptionsBuilder<AppDbContext>()
                .UseNpgsql(postgresFixture.GetConnectionString(Database))
                .Options);

        await context.Database.EnsureCreatedAsync(TestContext.Current.CancellationToken);

        // …
    }
}

The version is yours, not this package's

PostgresFixture is abstract and takes the image as a required constructor argument. There is no default: nothing in this package selects a PostgreSQL version, and no version is reachable without your naming one. The tags in these examples are illustration, not a fallback — delete the argument and the code does not compile.

That is deliberate. Which database version a repository tests against is a statement about the production database that repository targets, and it belongs beside that repository's code — a shared library choosing it for you is how tests and production drift apart without anyone deciding to. The argument is a full image reference, so a mirror or a private registry can be named too.

Pin by digest, not by tag. A tag is a name, and a name can be re-published against a different image; a digest is the image's content fingerprint and cannot be moved. So even an exact patch tag leaves "the same commit ran the same server" resting on nobody having moved it. A floating major like postgres:18 is worse — it is meant to move, and Docker will not re-pull a tag it already has, so a developer's weeks-old cache and a fresh machine disagree silently. A red test should mean a code change.

Read the digest of the image your production runs with:

docker pull postgres:18.4
docker inspect --format='{{index .RepoDigests 0}}' postgres:18.4

Keeping the tag in front of the digest costs nothing and keeps the line readable; only the digest binds.

What it does and does not do

  • Does: start one PostgreSQL server for the whole test assembly, on a random host port, and stop it when the assembly finishes.
  • Does not: create databases. GetConnectionString(name) only names one; creating it is yours to do — EnsureCreatedAsync, a migration run, or plain SQL.
  • Concurrency: test classes in one assembly share the server, so classes that may run at the same time must use distinct database names.

The bootstrap database, username and password inside the container are fixed by the package and not configurable: the server is reachable only on a random host port and lives for the length of one test assembly, so they carry no decision worth restating per repository.

Container is exposed for everything this fixture does not wrap — running a script, reading logs. It is disposed by the fixture; never dispose it from a test.

Using it couples you to Testcontainers, and that is deliberate. The property hands back that library's own type rather than something of ours, so a major version of Testcontainers is a breaking change for code that touches it — where code that stays on GetConnectionString is unaffected. The alternative was a set of narrow wrappers for needs nobody has demonstrated yet; an escape hatch you can see is better than one guessed at in advance. If you find yourself needing something specific through it, that is worth telling us: a named operation can then replace the raw handle.

Requirements

  • .NET 10. The package ships a net10.0 assembly only — a test project on an earlier target framework cannot use it.
  • A reachable Docker daemon. The image is pulled on first use if it is not already local.
  • xunit 3.2.x or 4.x. One package serves both lines: it uses only IAsyncLifetime and AssemblyFixture, whose shapes are identical across them, and the type you register has a parameterless constructor, so xunit 4's xUnit3005 rule is satisfied without any suppression. The dependency is on xunit.v3.extensibility.core alone, declared as a floor, so it imposes no test runner on you and does not hold you back from xunit 4.

Diagnostics

Testcontainers' own log output is forwarded to xunit's diagnostic messages, which is where a container that refuses to start explains itself. Switch them on in xunit.runner.json:

{ "diagnosticMessages": true }
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.2.7 48 9/19/2026
0.2.5 135 8/16/2026
0.2.3 107 8/15/2026
0.2.2 105 8/15/2026
0.2.1 100 8/15/2026