Nullean.Xunit.Partitions.v3
0.12.0
dotnet add package Nullean.Xunit.Partitions.v3 --version 0.12.0
NuGet\Install-Package Nullean.Xunit.Partitions.v3 -Version 0.12.0
<PackageReference Include="Nullean.Xunit.Partitions.v3" Version="0.12.0" />
<PackageVersion Include="Nullean.Xunit.Partitions.v3" Version="0.12.0" />
<PackageReference Include="Nullean.Xunit.Partitions.v3" />
paket add Nullean.Xunit.Partitions.v3 --version 0.12.0
#r "nuget: Nullean.Xunit.Partitions.v3, 0.12.0"
#:package Nullean.Xunit.Partitions.v3@0.12.0
#addin nuget:?package=Nullean.Xunit.Partitions.v3&version=0.12.0
#tool nuget:?package=Nullean.Xunit.Partitions.v3&version=0.12.0
Nullean.Xunit.Partitions.v3
<a href="https://www.nuget.org/packages/Nullean.Xunit.Partitions.v3/"><img src="https://img.shields.io/nuget/v/Nullean.Xunit.Partitions.v3?color=blue&style=plastic" /></a>
An xUnit v3 TestFramework implementation that introduces the concept of partitions for sharing long-lived state across tests.
This is the xUnit v3 version. For xUnit v2, use
Nullean.Xunit.Partitions.
Why partitions?
IPartitionFixture<TLifetime> lets tests inject a long-lived object (Docker container, database, Playwright browser, etc.) that is shared across multiple test classes.
- Only one partition runs at a time — partitions execute serially, so expensive resources don't compete.
- Tests within a partition run concurrently — unlike
ICollectionFixture<T>, partitions are not a concurrency barrier. - Just-in-time lifecycle —
InitializeAsyncis called right before a partition's tests run, andDisposeAsyncright after. This is more efficient than assembly fixtures which bootstrap at startup and dispose at shutdown. - Per-partition concurrency control — each
IPartitionLifetimecan declare its ownMaxConcurrency.
If you want to share a few (0–20) long-running objects over thousands of tests, this library is for you. If you have many test collections with only a few tests each, xUnit's native collection fixtures may be a better fit.
Setup
xUnit v3 test projects are executables. Your .csproj should look like:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="xunit.v3" Version="3.2.2" />
<PackageReference Include="Nullean.Xunit.Partitions.v3" Version="*" />
</ItemGroup>
</Project>
Register the test framework with an assembly-level attribute:
using Nullean.Xunit.Partitions.v3;
using Xunit;
[assembly: TestFramework(typeof(PartitionTestFramework))]
Usage
Define a partition lifetime — the shared state that will be initialized once and injected into all test classes that request it:
public class LongLivedObject : IPartitionLifetime
{
private static long _initialized;
private static long _disposed;
public long Initialized => _initialized;
public long Disposed => _disposed;
public ValueTask InitializeAsync()
{
Interlocked.Increment(ref _initialized);
return default;
}
public ValueTask DisposeAsync()
{
Interlocked.Increment(ref _disposed);
return default;
}
public int? MaxConcurrency => null;
public string FailureTestOutput() => "";
}
Test classes receive the shared instance via constructor injection by implementing IPartitionFixture<T>:
public class SharedState1Class(LongLivedObject state) : IPartitionFixture<LongLivedObject>
{
[Fact]
public void InitializedOnce() => state.Initialized.Should().Be(1);
[Fact]
public void NotDisposedYet() => state.Disposed.Should().Be(0);
}
public class SharedState2Class(LongLivedObject state) : IPartitionFixture<LongLivedObject>
{
[Fact]
public void InitializedOnce() => state.Initialized.Should().Be(1);
[Fact]
public void NotDisposedYet() => state.Disposed.Should().Be(0);
}
Both classes share a single LongLivedObject instance. Their tests run concurrently within the partition. DisposeAsync runs only after all tests in the partition complete.
Test classes without IPartitionFixture<T> are grouped into an implicit "no partition" group and run concurrently with default concurrency.
Providing options
Control partition and test filtering with a custom options class:
using Nullean.Xunit.Partitions.v3;
using Xunit;
[assembly: TestFramework(typeof(PartitionTestFramework))]
[assembly: PartitionOptions(typeof(MyOptions))]
public class MyOptions : PartitionOptions
{
public MyOptions()
{
// Only run partitions whose type name matches this regex
PartitionFilterRegex = "LongLivedObject";
// Only run test classes whose name matches this regex (null = all)
TestFilterRegex = null;
}
}
You can also override OnBeforeTestsRun() and OnTestsFinished(...) for custom logging or reporting.
Migrating from v2
| v2 | v3 |
|---|---|
[assembly: TestFramework(Partition.TestFramework, Partition.Assembly)] |
[assembly: TestFramework(typeof(PartitionTestFramework))] |
Task InitializeAsync() / Task DisposeAsync() |
ValueTask InitializeAsync() / ValueTask DisposeAsync() |
PartitionContext.TestException |
TestContext.Current.TestState (xUnit v3 built-in) |
return Task.CompletedTask; |
return default; |
Nullean.Xunit.Partitions namespace |
Nullean.Xunit.Partitions.v3 namespace |
| Test project is a class library | Test project is an executable (<OutputType>Exe</OutputType>) |
Requires xunit.runner.visualstudio + Microsoft.NET.Test.Sdk |
Self-hosting — no runner packages needed |
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. 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. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- xunit.v3.extensibility.core (>= 3.2.2)
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.12.0 | 32 | 2/17/2026 |