TUnit: Modern .NET Test Framework
TUnit is an open-source .NET test framework built by Thomas Hurst with source generation and NativeAOT (Ahead-of-Time Compilation) as first-class design constraints. Where xUnit, NUnit, and MSTest rely on reflection to discover and execute tests at runtime, TUnit’s source generator emits all discovery and wiring code at compile time. The result: no startup reflection overhead, full trimming compatibility, and a test runner that works correctly in NativeAOT-compiled applications.
What Sets TUnit Apart
Parallel by default. Tests run in parallel unless explicitly constrained. TUnit ships a rich set of attributes ([NotInParallel], [DependsOn], [MethodDataSource]) for managing test ordering and resource contention without disabling parallelism globally.
Source-generated test discovery. At build time, the TUnit source generator produces a static test catalog. There is no runtime assembly scanning, no reflection-based attribute discovery, and no hidden startup cost that scales with test count.
Built-in assertion library. TUnit ships its own Assert.* surface with async support, fluent chaining, and Roslyn analyzers that catch common assertion mistakes at compile time rather than at test run time.
AOT-compatible mocking. The companion library TUnit.Mocks provides source-generated mocks. No Castle.DynamicProxy, no runtime IL (Intermediate Language) emission. Mock.Of<T>() is the entry point, and all setups, verifications, and argument matchers are statically typed and resolved at compile time.
Compatibility and Migration
TUnit targets .NET 8 and later. It integrates with existing CI/CD tooling through standard dotnet test and supports adapter output for common reporting formats. TUnit.Mocks coexists with NSubstitute and Moq within the same solution, which makes incremental migration practical: new tests move to TUnit.Mocks while existing tests keep running unchanged.
Related Topics
TUnit sits at the intersection of Testing, Source Generators, and Mocking.

TUnit.Mocks: No Castle, No Reflection, No Drama
NSubstitute and Castle.DynamicProxy. That foundation is cracking: NativeAOT breaks it, trimming strips it, cold-start costs accumulate. TUnit.Mocks takes a different route: a source generator emits typed mocks at compile time, IService.Mock() (or Mock.Of<T>()) is the entry point, runtime reflection is gone.