NextUnit.Platform
3.0.0
dotnet add package NextUnit.Platform --version 3.0.0
NuGet\Install-Package NextUnit.Platform -Version 3.0.0
<PackageReference Include="NextUnit.Platform" Version="3.0.0" />
<PackageVersion Include="NextUnit.Platform" Version="3.0.0" />
<PackageReference Include="NextUnit.Platform" />
paket add NextUnit.Platform --version 3.0.0
#r "nuget: NextUnit.Platform, 3.0.0"
#:package NextUnit.Platform@3.0.0
#addin nuget:?package=NextUnit.Platform&version=3.0.0
#tool nuget:?package=NextUnit.Platform&version=3.0.0
NextUnit
A modern, high-performance test framework for .NET 10+ with zero-reflection execution and xUnit-style assertions.
This README, like the rest of the documentation on main, describes NextUnit as it stands there while pinning the
latest released version, so between releases it can mention an API the pinned version does not ship yet; to read it as
it stood for an earlier release, check out that release's git tag.
Features
- Zero-reflection execution - Source generators produce delegate-based test registry
- Familiar assertions -
Assert.Equal,Assert.True,Assert.Throws,Assert.Same,Assert.DoesNotThrow, etc. - Async tests -
Task,Task<T>,ValueTask, andValueTask<T>return types for tests and lifecycle hooks - Multi-scope lifecycle -
[Before]/[After]at Test, Class, Assembly, or Session level - Fine-grained parallelism -
[ParallelLimit(N)],[NotInParallel("key")],[ParallelGroup] - Execution priority -
[ExecutionPriority(N)]for controlling test execution order - Parameterized tests -
[Arguments],[TestData],[Matrix], and typed per-row metadata - Async data sources -
[TestData]acceptsIAsyncEnumerable<T>and task-wrapped collection members - Deferred data sources - opt a very large
[TestData]source out of discovery-time enumeration - Combined data sources -
[Values],[ValuesFromMember],[ValuesFrom<T>]with Cartesian product - Class data source -
[ClassDataSource<T>]with shared instance support - Category/Tag filtering -
[Category],[Tag]with CLI and environment variable support - Selective retry -
[Retry(N)], or[Retry<TPolicy>(N)]with an asyncIRetryPolicythat decides per exception; the attempt number is onITestContextand the attempt count reaches the failure output - Deterministic culture -
[Culture],[UICulture],[InvariantCulture]at assembly, class, or method level, restored after every test and isolated from tests running in parallel - Test dependencies -
[DependsOn]for ordered execution withProceedOnFailureoption - Explicit tests -
[Explicit]to exclude from default runs - Roslyn analyzers - Compile-time test validation
- Microsoft.Testing.Platform integration - Works with
dotnet run,dotnet test, and IDE test explorers - ASP.NET Core integration -
NextUnit.AspNetCorepackage for web API testing - Native AOT compatible
Quick Start
New Project
dotnet new install NextUnit.Templates
dotnet new nextunit -n MyProject.Tests
The generated project references only the NextUnit package and contains one passing example test.
Existing Project
dotnet add package NextUnit
Project Configuration
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="NextUnit" Version="3.0.0" />
</ItemGroup>
</Project>
Writing Tests
using NextUnit;
public class CalculatorTests
{
[Test]
public void Add_ReturnsSum()
{
Assert.Equal(4, 2 + 2);
}
[Test]
public void Divide_ThrowsOnZero()
{
Assert.Throws<DivideByZeroException>(() => { var x = 1 / 0; });
}
[Test]
[Arguments(2, 3, 5)]
[Arguments(-1, 1, 0)]
public void Add_Parameterized(int a, int b, int expected)
{
Assert.Equal(expected, a + b);
}
}
Running Tests
dotnet run --project MyProject.Tests # Run one test project
dotnet test # Run all tests when MTP is selected in global.json
With the .NET 10 SDK, dotnet test selects Microsoft.Testing.Platform at repository scope:
{
"test": {
"runner": "Microsoft.Testing.Platform"
}
}
NextUnit repositories can copy the checked-in global.json; dotnet run needs no repository-level
configuration.
Assertions
| Category | Methods |
|---|---|
| Basic | Equal, NotEqual, True, False, Null, NotNull |
| Identity | Same, NotSame, Fail |
| Collections | Contains, DoesNotContain, Empty, NotEmpty, Single, All |
| Strings | StartsWith, EndsWith, Contains |
| Numeric | InRange, NotInRange, Equal(expected, actual, precision), Equal(expected, actual, tolerance), NotEqual(expected, actual, tolerance) |
| Exceptions | Throws<T>, ThrowsAsync<T>, DoesNotThrow, DoesNotThrowAsync |
| Advanced | Equivalent, Subset, Disjoint |
Lifecycle Hooks
public class DatabaseTests
{
[Before(LifecycleScope.Test)] // Before each test
public void Setup() { }
[After(LifecycleScope.Test)] // After each test
public void Cleanup() { }
[Before(LifecycleScope.Class)] // Once before all tests in class
public void ClassSetup() { }
[Test]
public void MyTest() { }
}
Scopes: Test, Class, Assembly, Session
Parallel Execution
[NotInParallel] // Run tests serially
public class SlowTests { }
[ParallelLimit(2)] // Max 2 concurrent tests
public class ModerateTests { }
Filtering
[Category("Integration")]
[Tag("Slow")]
public class MyTests { }
# Environment variables
NEXTUNIT_INCLUDE_CATEGORIES=Integration dotnet run --project MyProject.Tests
NEXTUNIT_EXCLUDE_TAGS=Slow dotnet run --project MyProject.Tests
Expansion Limits
[Matrix], [Arguments], [Repeat], and parameter-level data sources ([Values],
[ValuesFromMember], [ValuesFrom]) multiply, so a small edit can ask for millions of test cases.
NextUnit caps those at 10000 test cases per test method and fails fast instead of expanding: the
generator reports NEXTUNIT013 at compile time, and discovery throws when a combined data source
resolves to more than the cap. Neither ever truncates -- a shortened run would report green over
tests that never ran.
The cap covers the expansions NextUnit performs itself. It does not limit how many rows a
[TestData] or [ClassDataSource] member returns, because that member is your code: bounding its
row count would not bound its running time, and a large row set is a supported case. For [TestData],
DeferredEnumeration keeps discovery cheap over a large source by reporting one placeholder and
enumerating rows only during execution; [ClassDataSource] has no deferred mode and always
materializes its rows at discovery.
Raise the cap per project for the generator, and per run for discovery:
<PropertyGroup>
<NextUnitMaxTestCasesPerMethod>50000</NextUnitMaxTestCasesPerMethod>
</PropertyGroup>
NEXTUNIT_MAX_TEST_CASES_PER_METHOD=50000 dotnet run --project MyProject.Tests
Leave both unset and the default applies. Set either one to anything that is not a positive 32-bit
integer -- 100O for 1000, a 0, a negative -- and NextUnit refuses it instead of falling back:
the generator reports NEXTUNIT014 and the build fails, and discovery throws before it resolves a
single data source. A typo in a cap is always looser than the value you typed, so accepting the
default in its place would quietly grant more than you asked for.
Neither setting overrides the other, because nothing reads both. NextUnitMaxTestCasesPerMethod is
the compile-time cap and only the generator sees it; NEXTUNIT_MAX_TEST_CASES_PER_METHOD is the
discovery-time cap and only the test host sees it. Each is validated where it is read, so a valid
property does not rescue an unusable environment variable, and a valid environment variable does not
rescue an unusable property. Raising one does not raise the other either -- set both when you want a
larger cap in both places.
Performance
The checked-in comparison suite runs 127 tests with shared bodies through native MTP executables. A 21-round cyclic comparison balances execution order across five major frameworks and Native AOT variants of NextUnit and TUnit. The current snapshot is from the PR #160 GitHub Actions run on Ubuntu 24.04:
| Framework | Version | Median | Median / NextUnit |
|---|---|---|---|
| NextUnit (AOT) | PR #160 checkout (1.15.1 assembly) | 21.51ms | 0.07x |
| TUnit (AOT) | 1.61.15 | 27.45ms | 0.09x |
| NextUnit | PR #160 checkout (1.15.1 assembly) | 311.43ms | 1.00x |
| MSTest | 4.3.2 | 438.73ms | 1.41x |
| NUnit | 4.6.1 | 512.90ms | 1.65x |
| xUnit | 3.2.2 | 551.40ms | 1.77x |
| TUnit | 1.61.15 | 555.00ms | 1.78x |
The workload is startup-heavy and machine-specific, so these ratios are not universal performance claims. See the methodology and limitations, generated results, and raw timings.
Documentation
- Getting Started
- Migration from xUnit
- Migration from NUnit
- Migration from MSTest
- ASP.NET Core Testing
- Best Practices
- Performance Analysis
- CI/CD Integration
- Changelog
Sample Projects
- Class Library Testing - Business logic testing patterns
- Console App Testing - CLI argument parsing, file processing
- Framework Tests - All NextUnit features demonstrated
- Web API Testing - ASP.NET Core integration testing with
WebApplicationTest<T>
Contributing
- Open an issue to discuss your idea
- Fork and create a feature branch
- Write tests for your changes
- Submit a PR
Note: English-only for code, comments, and documentation.
dotnet build --configuration Release
dotnet test --project samples/NextUnit.SampleTests/NextUnit.SampleTests.csproj
License
Acknowledgments
Inspired by TUnit (architecture), xUnit (assertions), and NUnit/MSTest.
| Product | Versions 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. |
-
net10.0
- Microsoft.Testing.Platform (>= 2.3.3)
- NextUnit.Core (>= 3.0.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on NextUnit.Platform:
| Package | Downloads |
|---|---|
|
NextUnit
NextUnit - A modern, high-performance test framework for .NET 10+ that combines TUnit's architecture with xUnit's familiar assertions. This meta-package includes all required components for getting started with NextUnit. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 3.0.0 | 0 | 8/21/2026 |
| 2.0.0 | 269 | 8/11/2026 |
| 1.19.1 | 195 | 8/10/2026 |
| 1.19.0 | 154 | 8/4/2026 |
| 1.18.0 | 272 | 7/26/2026 |
| 1.17.0 | 212 | 7/25/2026 |
| 1.16.0 | 180 | 7/25/2026 |
| 1.15.1 | 226 | 7/22/2026 |
| 1.13.0 | 154 | 1/24/2026 |
| 1.12.0 | 121 | 1/24/2026 |
| 1.11.0 | 126 | 1/24/2026 |
| 1.10.0 | 128 | 1/24/2026 |
| 1.9.0 | 133 | 1/22/2026 |
| 1.8.0 | 136 | 1/22/2026 |
| 1.7.1 | 133 | 1/19/2026 |
| 1.7.0 | 123 | 1/18/2026 |
| 1.6.9 | 130 | 1/18/2026 |
| 1.6.8 | 128 | 1/18/2026 |
| 1.6.7 | 123 | 1/18/2026 |
| 1.6.6 | 137 | 1/14/2026 |
See https://github.com/crane-valley/NextUnit/blob/main/CHANGELOG.md for release notes.