Skip to main content

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.