TU

Development patterns and setup instructions for TUnit 1.45.x in .NET 10 environments.

Install

mkdir -p .claude/skills/tunit-usage && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/15970" && unzip -o skill.zip -d .claude/skills/tunit-usage && rm skill.zip

Installs to .claude/skills/tunit-usage

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

TUnit 1.45.x test framework patterns for .NET 10. Use when setting up a TUnit test project, writing tests, skipping tests conditionally, wiring session-level fixtures, or troubleshooting TUnit API issues. Covers: project setup, skip mechanism, Before/After hooks, Assert syntax, ClassDataSource shari
300 chars · catalog description✓ has a “when” triggerlonger than Claude Code's old 250-char listing cap (fine on current versions)
Intermediate

Key capabilities

  • Set up a TUnit test project for .NET 10
  • Write asynchronous tests using `async Task` and `[Test]` attribute
  • Use TUnit Assert syntax for various checks
  • Implement conditional test skipping using `SkipTestException`
  • Wire session-level fixtures with `[Before(TestSession)]` and `[After(TestSession)]`
  • Share fixtures across classes using `ClassDataSource`

How it works

This skill provides usage patterns for the TUnit 1.45.x test framework, covering project setup, test writing, assertion syntax, conditional skipping, and session-level fixtures.

Inputs & outputs

You give it
C# code for tests and fixtures
You get back
Executable TUnit tests with defined behaviors and assertions

When to use tunit-usage

  • Set up TUnit project
  • Write async tests
  • Implement session fixtures
  • Configure test runner

About this skill

TUnit 1.45.x Usage Patterns

Project Setup

global.json — required to enable Microsoft.Testing.Platform runner

{
  "sdk": { "version": "10.0.100", "rollForward": "latestMinor" },
  "test": { "runner": "Microsoft.Testing.Platform" }
}

Test project .csproj

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>           <!-- Required for TUnit -->
    <TargetFramework>net10.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <EnforceCodeStyleInBuild>false</EnforceCodeStyleInBuild>
    <NoWarn>$(NoWarn);CS1591</NoWarn>      <!-- XML docs not required in tests -->
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="TUnit" />   <!-- Version from Directory.Packages.props -->
  </ItemGroup>
</Project>

Directory.Packages.props entry

<PackageVersion Include="TUnit" Version="1.45.22" />

Writing Tests

using TUnit.Core;

public sealed class MyTests
{
    [Test]
    public async Task Something_GivenCondition_ReturnsExpected()
    {
        var result = 2 + 2;
        await Assert.That(result).IsEqualTo(4);
    }
}
  • No base class required
  • Methods must be async Task and decorated with [Test]
  • One await Assert.That(...) per logical assertion

Assert Syntax

await Assert.That(value).IsEqualTo(expected);
await Assert.That(value).IsNotEqualTo(unexpected);
await Assert.That(value).IsTrue();
await Assert.That(value).IsFalse();
await Assert.That(value).IsNull();
await Assert.That(value).IsNotNull();
await Assert.That(value).IsGreaterThan(n);
await Assert.That(value).IsTypeOf<SomeType>();
await Assert.That(collection).HasCount().EqualTo(n);  // NOT .HasCount(n)
await Assert.That(str).Contains("substring");

// Exceptions
await Assert.That(() => DoSomething()).Throws<ArgumentNullException>();
await Assert.That(() => DoSomething()).Throws<MyException>()
    .WithMessageContaining("expected fragment");

Skipping Tests

The skip exception namespace — COMMON PITFALL

// WRONG — CS0246, type not in TUnit.Core directly
using TUnit.Core;
throw new SkipTestException("reason");

// CORRECT — it lives in TUnit.Core.Exceptions
using TUnit.Core.Exceptions;
throw new SkipTestException("reason");

Conditional skip inside a test

[Test]
public async Task MyTest()
{
    if (!someCondition)
    {
        throw new SkipTestException("Condition not met on this machine.");
    }
    // ... rest of test
}

Reusable skip helper

using TUnit.Core.Exceptions;

internal static class TestEnvironment
{
    internal static Task SkipIfUnavailableAsync()
    {
        if (!IsAvailable)
        {
            throw new SkipTestException("Resource not available.");
        }
        return Task.CompletedTask;
    }
}

Session-Level Fixtures (run once per test run)

Use a static class with [Before(TestSession)] / [After(TestSession)]. No base class, no interface needed.

using TUnit.Core;

internal static class GlobalHooks
{
    [Before(TestSession)]
    public static async Task InitializeAsync()
    {
        // Runs once before any test in the session
        await Task.Run(() => MyRuntime.Initialize());
    }

    [After(TestSession)]
    public static async Task ShutdownAsync()
    {
        // Runs once after all tests complete
        if (MyRuntime.IsInitialized)
        {
            await Task.Run(() => MyRuntime.Shutdown());
        }
    }
}

Other hook granularities

AttributeRuns
[Before(TestSession)]Once before entire test run
[After(TestSession)]Once after entire test run
[Before(Class)]Before each test class
[After(Class)]After each test class
[Before(Test)]Before each individual test
[After(Test)]After each individual test

Integration Test Base Class Pattern

internal abstract class IntegrationTestBase
{
    [Before(Test)]
    public async Task RequireResourceAsync()
    {
        await TestEnvironment.SkipIfUnavailableAsync();
    }
}

public sealed class MyIntegrationTests : IntegrationTestBase
{
    [Test]
    public async Task Does_Something_WithRealResource()
    {
        // Auto-skips via base class [Before(Test)] if resource unavailable
    }
}

ClassDataSource — Shared Fixtures

// SharedType enum values in TUnit 1.45:
//   None, PerClass, PerAssembly, PerTestSession
// NOTE: SharedType.Globally does NOT exist — use PerTestSession instead

[ClassDataSource<MyFixture>(Shared = SharedType.PerTestSession)]
public class MyTests
{
    // TUnit injects MyFixture as constructor parameter or property
}

To make the fixture initialize async, implement IAsyncInitializer from TUnit.Core and IAsyncDisposable:

using TUnit.Core;

internal sealed class MyFixture : IAsyncInitializer, IAsyncDisposable
{
    public async Task InitializeAsync()
    {
        await SetUpAsync();
    }

    public async ValueTask DisposeAsync()
    {
        await TearDownAsync();
    }
}

Common Pitfalls

ProblemCauseFix
SkipTestException not foundWrong namespaceusing TUnit.Core.Exceptions;
SharedType.Globally not foundDoesn't existUse SharedType.PerTestSession
IAsyncInitializer not foundMissing usingusing TUnit.Core;
Test project won't runMissing <OutputType>Exe</OutputType>Add to csproj
Tests not discoveredMissing global.json runnerAdd "test": { "runner": "Microsoft.Testing.Platform" }
.HasCount(n) compile errorAPI changedUse .HasCount().EqualTo(n)
Constant bool assertion errorTUnit analyzerUse IsTypeOf<bool>() or just remove trivial assertions

When not to use it

  • When using a TUnit version other than 1.45.x
  • When developing for a .NET version other than 10
  • When not using the Microsoft.Testing.Platform runner

Prerequisites

Microsoft.NET.SdkTUnit packageMicrosoft.Testing.Platform runner

Limitations

  • Specific to TUnit 1.45.x
  • Specific to .NET 10
  • Requires `Microsoft.Testing.Platform` runner

How it compares

This skill offers specific TUnit 1.45.x patterns for .NET 10, providing detailed guidance for test project configuration and test writing that differs from general .NET testing frameworks.

Compared to similar skills

tunit-usage side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
tunit-usage (this skill)02moNo flagsIntermediate
csharp-pro94moNo flagsIntermediate
performance-benchmark35moNo flagsIntermediate
run-device-tests32moReviewAdvanced

Try saying

Example prompts that trigger this skill in your AI assistant.

You might also like

csharp-pro

sickn33

Write modern C# code with advanced features like records, pattern matching, and async/await. Optimizes .NET applications, implements enterprise patterns, and ensures comprehensive testing. Use PROACTIVELY for C# refactoring, performance optimization, or complex .NET solutions.

953

performance-benchmark

dotnet

Generate and run ad hoc performance benchmarks to validate code changes. Use this when asked to benchmark, profile, or validate the performance impact of a code change in dotnet/runtime.

328

run-device-tests

dotnet

Build and run .NET MAUI device tests locally with category filtering. Supports iOS, MacCatalyst, Android on macOS; Android, Windows on Windows. Use TestFilter to run specific test categories.

325

backend-testing

exceptionless

Backend testing with xUnit, Foundatio.Xunit, integration tests with AppWebHostFactory, FluentClient, ProxyTimeProvider for time manipulation, and test data builders. Keywords: xUnit, Fact, Theory, integration tests, AppWebHostFactory, FluentClient, ProxyTimeProvider, TimeProvider, Foundatio.Xunit, TestWithLoggingBase, test data builders

316

bunit-test-migration

FritzAndFriends

Migrate bUnit test files from deprecated beta API (1.0.0-beta-10) to bUnit 2.x stable API. Use this when working on .razor test files in BlazorWebFormsComponents.Test that contain old patterns like TestComponentBase, Fixture, or SnapshotTest.

110

deployment-e2e-testing

dotnet

Guide for writing Aspire deployment end-to-end tests. Use this when asked to create, modify, or debug deployment E2E tests that deploy to Azure.

32

Search skills

Search the agent skills registry