TUnit Documentation

website·Indexed 33 days ago

https://tunit.dev

A comprehensive, fluent assertion library for .NET. TUnit provides expressive assertions for boolean values, collections, dictionaries, DateTime, numeric types, strings, and async Tasks. It features support for custom assertions via source generators, member assertions for object properties, and an optional 'Should' syntax package for a FluentAssertions-style experience.

Tokens
133.2K
Snippets
720
Records
841
Agent score
68%

What's inside TUnit

  1. Overview of TUnit Argument Matchers

    Argument matchers in TUnit control which method calls a setup or verification matches. They are used identically in both setup (Returns, Throws) and verification (WasCalled) contexts. TUnit.Mocks automatically imports the Arg class via global using static, allowing matcher methods to be called directly without the Arg. prefix.
  2. Overview of TUnit testing framework

    TUnit is a testing framework for C# / .NET designed for unit, integration, and acceptance testing. It is built on Microsoft.Testing.Platform and focuses on performance through source generation and compile-time optimizations. Key features include flexible test data injection (new or shared instances) and lifecycle hooks that run before and after tests.
  3. Overview of TUnit Execution Modes

    TUnit supports two execution modes for test discovery and execution:

    1. Source Generation Mode (Default): Uses compile-time source generation. It provides optimal performance, type safety, and is required for full Native AOT compatibility. This is the standard mode for C# projects.
    2. Reflection Mode: Uses traditional runtime reflection. This is necessary for scenarios where source generation is unsuitable (e.g., bUnit with Razor components) or for languages where source generation is not supported (F# and VB.NET).
  4. Overview of TUnit Assertion Categories

    TUnit provides a fluent assertion library categorized by the type of check being performed. Common assertion categories include equality, numeric comparison, null/default checks, boolean validation, string manipulation, collection analysis, exception handling, type checking, and asynchronous operation timing.
    // Equality
    IsEqualTo(), IsNotEqualTo()
    
    // Comparison
    IsGreaterThan(), IsLessThan(), IsBetween()
    
    // Null/Default
    IsNull(), IsNotNull(), IsDefault()
    
    // Boolean
    IsTrue(), IsFalse()
    
    // Strings
    Contains(), StartsWith(), Matches()
    
    // Collections
    Contains(), Count(), All(), Any()
    
    // Exceptions
    Throws<T>(), ThrowsNothing()
    
    // Types
    IsTypeOf<T>(), IsAssignableTo<T>()
    
    // Async
    CompletesWithin()
  5. Build tests with Native AOT or as single-file applications

    Because TUnit discovers tests at compile time via source generation rather than using runtime reflection, test projects can be built as Native AOT or single-file applications.
  6. Understand the benefits of source-generated mocks in TUnit.Mocks

    TUnit.Mocks utilizes source generation at compile time rather than runtime proxy generation. This approach provides several technical advantages:

    1. Native AOT & IL Trimming Compatibility: Because implementations are generated at compile time, it avoids the need for dynamic assembly emission.
    2. Reduced Overhead: Eliminates runtime proxy generation and reflection-based method dispatch.
    3. Performance: Provides execution benefits for standard .NET environments by removing the overhead associated with runtime proxies.
  7. Benefits of TUnit source generation for AOT compatibility

    TUnit's source generation mode improves test execution by resolving all types at compile time, eliminating the need for runtime type introspection. This results in improved execution performance, reduced memory allocations via strongly-typed delegates, and better overall code optimization by the compiler and runtime compared to reflection-based testing approaches.
  8. Access and use TestContext during test execution

    All tests in TUnit have access to a TestContext object via the static TestContext.Current property. This context provides metadata about the test (name, containing class, categories) and execution details. The Execution.Result property is available within AfterEachTest methods to conditionally execute logic based on the test outcome (e.g., taking a screenshot on failure).
    // Check for a custom property
    if (TestContext.Current?.Metadata.TestDetails.CustomProperties.ContainsKey("SomeProperty") == true)
    {
        // Do something
    }
    
    // Conditional cleanup based on test failure
    if (TestContext.Current?.Execution.Result?.State == TestState.Failed)
    {
        // Take a screenshot
    }
  9. Key architectural differences between MSTest and TUnit

    When migrating from MSTest to TUnit, keep these fundamental changes in mind:

    1. Async by Default: Tests and assertions are typically async Task and require await.
    2. No Class Attribute: The [TestClass] attribute is not required in TUnit.
    3. Fluent API: Assertions use the Assert.That() pattern.
    4. Context Injection: TestContext is passed as a method parameter, not as a class property.
  10. Correlate SUT logs to tests via OpenTelemetry

    By default, AspireFixture runs an OTLP receiver to correlate System Under Test (SUT) logs to the specific test that triggered them. When CreateHttpClient is used, the request includes W3C traceparent and baggage headers (including tunit.test.id). The SUT's OpenTelemetry SDK exports logs with the same TraceId, allowing TUnit to route logs to the correct test output even during concurrent execution.
  11. Visualize distributed traces in TUnit HTML reports

    TUnit HTML reports automatically capture and display trace spans from any .NET library (requiring .NET 8+) that uses System.Diagnostics.Activity.

    Because TUnit wraps each test body in a root System.Diagnostics.Activity, any child spans created by libraries like HttpClient, ASP.NET Core, or EF Core are automatically nested under the test's root span and rendered as a waterfall timeline in the report's test detail view. No additional configuration is required.

    [Test]
    public async Task GetUsers_ReturnsOk()
    {
        var client = Factory.CreateClient();
        // The following call emits spans captured automatically by TUnit
        var response = await client.GetAsync("/api/users"); 
        await Assert.That(response.StatusCode).IsEqualTo(HttpStatusCode.OK);
    }
  12. TUnit Performance Benchmark Methodology

    TUnit ensures fair and reproducible performance benchmarks by adhering to three core principles:

    1. Real-World Scenarios: Tests use actual assertion logic, real data source patterns, and typical setup/teardown workflows rather than artificial micro-benchmarks.
    2. Fair Comparison: All compared frameworks implement identical test logic, including the same methods, data inputs, assertion complexity, and equivalent configurations.
    3. Statistical Rigor: Benchmarks are powered by BenchmarkDotNet, utilizing multiple iterations, statistical outlier detection, and excluding warm-up phases from measurements.