TUnit Framework Core Features
1. Source Generator-Driven Test Discovery
The biggest difference between TUnit and traditional testing frameworks is that it uses a Source Generator atcompile timeto complete test discovery, avoiding reflection costs, fully supporting Native AOT, and providing faster startup time.
// TUnit 在編譯時期就透過 Source Generator 產生測試註冊程式碼
public class ModernTests
{
[Test] // 編譯時期就被處理和最佳化
public async Task TestMethod()
{
await Assert.That(true).IsTrue();
}
}
2. AOT (Ahead-of-Time) Compilation Support
傳統 JIT:C# 原始碼 → IL 中間碼 → 執行時期 JIT 編譯 → 機器碼 → 執行
AOT: C# 原始碼 → 編譯時期直接產生 → 機器碼 → 直接執行
AOT advantages: ultra-fast startup time, smaller memory footprint, predictable performance, and better suitability for containerized deployment. Large projects can achieve 10-30x startup time improvement.
3. Microsoft.Testing.Platform Adoption
TUnit is built on Microsoft's latest Microsoft.Testing.Platform, rather than the traditional VSTest platform.
Important note: TUnit projectsdo not needandshould notinstall the Microsoft.NET.Test.Sdk package.
4. Parallel Execution by Default
TUnit enables parallel execution by default; when needed, you can use [NotInParallel("GroupName")] to control specific test groups to run sequentially.
TUnit Project Creation
Supports manual creation (console template + TUnit package) or using the TUnit Template (dotnet new tunit, recommended). The project needs to configure the csproj (TUnit package, IsTestProject) and GlobalUsings.cs. All test methodsmust be asynchronous(async Task)。
For complete project creation steps and csproj examples, see references/project-setup.md
Test Attributes and Parameterization
Basic Test [Test]
TUnit uniformly uses the [Test] attribute, unlike xUnit which distinguishes between [Fact] and [Theory]:
[Test]
public async Task Add_輸入1和2_應回傳3()
{
var calculator = new Calculator();
var result = calculator.Add(1, 2);
await Assert.That(result).IsEqualTo(3);
}
Parameterized Test [Arguments]
[Test]
[Arguments(1, 2, 3)]
[Arguments(-1, 1, 0)]
[Arguments(0, 0, 0)]
public async Task Add_多組輸入_應回傳正確結果(int a, int b, int expected)
{
var calculator = new Calculator();
var result = calculator.Add(a, b);
await Assert.That(result).IsEqualTo(expected);
}
TUnit.Assertions Assertion System
TUnit adopts a fluent assertion design, and all assertions are asynchronous. It supports equality, boolean, numeric comparison, string, collection, exception, and many other assertions, and can combine conditions via And / Or .
await Assert.That(actual).IsEqualTo(expected);
await Assert.That(email).Contains("@").And.EndsWith(".com");
await Assert.That(() => action()).Throws<InvalidOperationException>();
For complete assertion types and examples, see references/tunit-assertions-detail.md
Test Lifecycle Management
TUnit supports the constructor / Dispose pattern, as well as [Before(Test)]、[Before(Class)]、[After(Test)]、[After(Class)] and other attributes.
執行順序:Before(Class) → 建構式 → Before(Test) → 測試方法 → After(Test) → Dispose → After(Class)
For complete lifecycle examples and attribute comparison tables, see references/lifecycle-management.md
Parallel Execution Control and xUnit Migration
TUnit runs all tests in parallel by default; use [NotInParallel] to control specific groups to run sequentially. It provides a complete xUnit → TUnit syntax comparison table, migration examples, CLI execution commands, and IDE integration settings.
For complete concurrency control, syntax comparison, and migration examples, see references/xunit-migration.md
Performance Comparison
| Scenario | xUnit | TUnit | TUnit AOT | Performance Improvement |
|---|---|---|---|---|
| Simple Test Execution | 1,400ms | 1,000ms | 60ms | 23x (AOT) |
| Asynchronous Tests | 1,400ms | 930ms | 26ms | 54x (AOT) |
| Parallel Tests | 1,425ms | 999ms | 54ms | 26x (AOT) |
Common Issues and Solutions
- Package Compatibility — Remove
Microsoft.NET.Test.Sdk, TUnit uses the new testing platform - IDE Integration Issues — Confirm the IDE version supports Microsoft.Testing.Platform and enable the relevant preview features
- Forgotten async assertions — All assertions require
await, and test methods must beasync Task
Applicable Scenario Assessment
Suitable for using TUnit
- Brand-new projects: No legacy baggage
- High performance requirements: Large test suites (1000+ tests)
- Modern tech stack: Using .NET 8+, planning to adopt AOT
- Heavy CI/CD usage: Test execution time directly affects deployment frequency
- Containerized deployment: Fast startup time is important
Not recommended for now
- Legacy projects: Already have a large number of xUnit tests
- Conservative teams: Need stability over innovation
- Complex test ecosystem: Heavy use of xUnit-specific packages
- Older .NET: Still on .NET 6/7
Output Format
- Generate TUnit test classes (including [Test] and [Arguments] attributes)
- Generate .csproj configuration (TUnit package references)
- Provide GlobalUsings.cs configuration
- Include a migration code comparison from xUnit to TUnit
Reference Resources
Original Article
The content of this skill is distilled from the article series "Old-School Software Engineer's Testing Practice - 30-Day Challenge":
- Day 28 - TUnit Getting Started - Exploring the Next-Generation .NET Testing Framework
- Ironman Series article:https://ithelp.ithome.com.tw/articles/10377828
- Sample code:https://github.com/kevintsengtw/30Days_in_Testing_Samples/tree/main/day28
Official Resources
Microsoft Official Documentation
Related Skills
dotnet-testing-advanced-tunit-advanced- TUnit Advanced Featuresdotnet-testing-advanced-xunit-upgrade-guide- xUnit Upgrade Guidedotnet-testing-xunit-project-setup- xUnit Project Setup (for comparison)