GitHub - thomhurst/TUnit: A modern, fast and flexible .NET testing framework (original) (raw)

TUnit

A modern .NET testing framework. Tests are source-generated at compile time, run in parallel by default, and support Native AOT — all built on Microsoft.Testing.Platform.

Features

Getting Started

dotnet new install TUnit.Templates dotnet new TUnit -n "MyTestProject" cd MyTestProject dotnet run

Manual Installation

Getting Started Guide · Migration Guides

Examples

Basic test with assertions

[Test] public async Task Parsing_A_Valid_Date_Succeeds() { var date = DateTime.Parse("2025-01-01");

await Assert.That(date.Year).IsEqualTo(2025);
await Assert.That(date.Month).IsEqualTo(1);

}

Data-driven tests

[Test] [Arguments("user1@test.com", "ValidPassword123")] [Arguments("user2@test.com", "AnotherPassword456")] [Arguments("admin@test.com", "AdminPass789")] public async Task User_Login_Should_Succeed(string email, string password) { var result = await authService.LoginAsync(email, password); await Assert.That(result.IsSuccess).IsTrue(); }

// Matrix — generates a test for every combination (9 total here) [Test] [MatrixDataSource] public async Task Database_Operations_Work( [Matrix("Create", "Update", "Delete")] string operation, [Matrix("User", "Product", "Order")] string entity) { await Assert.That(await ExecuteOperation(operation, entity)) .IsTrue(); }

Hooks, dependencies, and retry

[Before(Class)] public static async Task SetupDatabase(ClassHookContext context) { await DatabaseHelper.InitializeAsync(); }

[Test] [MethodDataSource(nameof(GetTestUsers))] public async Task Register_User(string username, string password) { ... }

[Test, DependsOn(nameof(Register_User))] [Retry(3)] public async Task Login_With_Registered_User(string username, string password) { // Guaranteed to run after Register_User passes }

Custom attributes

Extend built-in base classes to create your own skip conditions, retry logic, and more:

public class WindowsOnlyAttribute : SkipAttribute { public WindowsOnlyAttribute() : base("Windows only") { }

public override Task<bool> ShouldSkip(TestContext testContext)
    => Task.FromResult(!OperatingSystem.IsWindows());

}

[Test, WindowsOnly] public async Task Windows_Specific_Feature() { ... }

See the documentation for more examples, including custom retry logic and data sources.

IDE Support

IDE Notes
Visual Studio 2022 (17.13+) Works out of the box
Visual Studio 2022 (earlier) Enable "Use testing platform server mode" in Tools > Manage Preview Features
JetBrains Rider Enable "Testing Platform support" in Settings > Build, Execution, Deployment > Unit Testing > Testing Platform
VS Code Install C# Dev Kit and enable "Use Testing Platform Protocol"
CLI Works with dotnet test, dotnet run, and direct execution

Packages

Package Purpose
TUnit Start here — the full framework (Core + Engine + Assertions)
TUnit.Core Shared test library components without an execution engine
TUnit.Engine Execution engine for test projects
TUnit.Assertions Standalone assertions — works with other test frameworks too
TUnit.Assertions.Should Optional FluentAssertions-style value.Should().BeEqualTo(...) syntax over TUnit.Assertions (beta)
TUnit.Mocks Source-generated, AOT-compatible mocking framework — works with any test runner
TUnit.Mocks.Http HttpClient mocking helpers built on TUnit.Mocks
TUnit.Mocks.Logging ILogger capture/verification helpers built on TUnit.Mocks
TUnit.AspNetCore ASP.NET Core integration — WebApplicationFactory-based test fixtures
TUnit.Aspire Aspire integration — distributed app host fixtures with OpenTelemetry capture
TUnit.Playwright Playwright integration with automatic browser lifecycle management

Migrating from xUnit, NUnit, or MSTest?

The syntax will feel familiar. For example, xUnit's [Fact] becomes [Test], and [Theory] + [InlineData] becomes [Test] + [Arguments]. See the migration guides for full details: xUnit · NUnit · MSTest.

Community