agentskills.codes
TU

tunit-usage

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

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)

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

Search skills

Search the agent skills registry