Engine Modes
TUnit supports two execution modes, providing flexibility for different development and deployment scenarios.
Execution Modes
TUnit can run in two modes:
- Source Generation Mode (Default): Uses compile-time source generation for test discovery and execution, providing optimal performance and compile-time safety
- Reflection Mode: Traditional runtime reflection-based test discovery and execution, enabled with the
--reflection
command-line flag
When publishing with Native AOT, the source generation mode provides additional performance benefits and full AOT compatibility.
The Reflection mode allows discovery of test cases that have been source generated by something other than TUnit, though, for example .razor files in bUnit.
Source Generation Mode (Default)
By default, TUnit always uses source generation for test discovery and execution:
- Compile-Time Generation: All test discovery logic is generated at compile time
- Better Performance: Faster than reflection-based execution
- Type Safety: Compile-time validation of test configurations and data sources
- No Runtime Reflection: Eliminates the overhead of runtime type discovery
This is the standard mode used for all builds, whether debugging, running tests, or publishing. When you publish with Native AOT, you get additional performance benefits, but the underlying source generation logic remains the same.
Reflection Mode
Reflection mode can be explicitly enabled using the --reflection
command-line flag:
- Runtime Discovery: Tests are discovered at runtime using reflection
- Dynamic Execution: Uses traditional reflection-based test invocation
- Compatibility: Useful for scenarios where source generation may not be suitable
- Legacy Support: Maintains compatibility with reflection-dependent test patterns
Enable reflection mode by running:
dotnet test -- --reflection
Alternatively, setting the environment variable TUNIT_EXECUTION_MODE
to reflection
enables the reflection engine mode globally.
Native AOT Support
When publishing with Native AOT, TUnit's source generation mode provides additional benefits:
- Full AOT Compatibility: The source-generated code is fully compatible with Native AOT compilation
- Enhanced Performance: Better performance compared to reflection-based execution
- Reduced Binary Size: No reflection metadata needed, resulting in smaller executables
- Faster Startup: No runtime type discovery overhead
Note: These AOT-specific benefits only apply when actually publishing with Native AOT. Regular builds use the same source generation logic but without the native compilation optimizations.
How Source Generation Works
TUnit's source generation creates strongly-typed delegates for all test operations at compile time:
- Test Invocation: Type-specific delegates instead of generic object arrays
- Data Sources: Specialized factory methods with exact return types
- Property Injection: Generated property setters with dependency resolution
- Hook Methods: Strongly-typed hook delegates with proper async support
Publishing with Native AOT
To use TUnit with Native AOT:
<PropertyGroup>
<PublishAot>true</PublishAot>
</PropertyGroup>
Then publish your project:
dotnet publish -c Release
Configuration
TUnit uses optimized defaults for all features. The only configurable option is verbose diagnostics for troubleshooting source generation issues:
EditorConfig (.editorconfig)
# Enable verbose diagnostics (default: false)
tunit.enable_verbose_diagnostics = true
MSBuild Property
<PropertyGroup>
<TUnitEnableVerboseDiagnostics>true</TUnitEnableVerboseDiagnostics>
</PropertyGroup>
Compatibility
C# Projects: Full support with source generation F# Projects: Falls back to reflection mode (source generation not supported) VB.NET Projects: Falls back to reflection mode (source generation not supported)
For F# and VB.NET projects, TUnit automatically uses reflection mode since source generation is only available for C# projects. For better performance with F# or VB.NET code, create a separate C# test project that references your F#/VB.NET libraries and write tests there.