PluginBench
Skill
Official
Review
Audit score 70

csharp-tunit

github/awesome-copilot

Reference guide for writing modern, fast C# unit tests with TUnit, including data-driven testing and xUnit migration tips.

What is csharp-tunit?

This skill provides best-practice guidance for writing unit tests with the TUnit framework in C#, covering project setup, test structure, fluent async assertions, data-driven testing, and advanced features like parallel execution and lifecycle hooks. It also includes a migration guide for moving existing xUnit tests to TUnit.

  • Outlines TUnit project setup and naming conventions for test projects and classes
  • Describes test structure conventions including [Test] attribute, AAA pattern, and naming
  • Details lifecycle hooks ([Before]/[After] at Test, Class, Assembly, TestSession levels)
  • Explains fluent, async assertion syntax via Assert.That() including chaining with .And/.Or
  • Covers data-driven testing options ([Arguments], [MethodData], [ClassData], custom ITestDataSource)
  • Lists advanced features like [Repeat], [Retry], [ParallelLimit], [Skip], [DependsOn], [Timeout]

How to install csharp-tunit

npx skills add https://github.com/github/awesome-copilot --skill csharp-tunit
Prerequisites
  • .NET 8.0 SDK or higher
  • A separate test project referencing TUnit and TUnit.Assertions packages
Claude Code
Cursor
Windsurf
Cline

How to use csharp-tunit

  1. 1.Create a separate test project named [ProjectName].Tests targeting .NET 8.0 or higher
  2. 2.Reference the TUnit and TUnit.Assertions packages
  3. 3.Create test classes matching the classes under test (e.g., CalculatorTests)
  4. 4.Write test methods using [Test] and follow the Arrange-Act-Assert pattern, naming them MethodName_Scenario_ExpectedBehavior
  5. 5.Use [Before(Test)]/[After(Test)] or class/assembly-level hooks for setup and teardown
  6. 6.Write assertions using await Assert.That(...) fluent syntax
  7. 7.Add data-driven tests with [Arguments], [MethodData], or [ClassData] as needed
  8. 8.Apply advanced attributes like [Repeat], [Retry], [Skip], [DependsOn], or [Timeout] where relevant

Use cases

Good for
  • Setting up a new TUnit test project for a .NET application
  • Writing data-driven tests using [Arguments], [MethodData], or [ClassData]
  • Migrating an existing xUnit test suite to TUnit
  • Configuring test lifecycle hooks for setup/teardown at test, class, or assembly scope
  • Tuning parallel test execution and retry/timeout behavior for a test suite
Who it's for
  • .NET developers writing or maintaining unit tests in C#
  • Teams evaluating or adopting TUnit as a testing framework
  • Developers migrating an existing xUnit test suite to TUnit
  • Engineers needing guidance on data-driven and parallel test execution patterns

csharp-tunit FAQ

Do I need a special test class attribute in TUnit?

No. Unlike xUnit/NUnit, TUnit does not require a test class attribute; just use [Test] on test methods.

How do assertions work in TUnit?

Assertions use a fluent, asynchronous syntax like `await Assert.That(value).IsEqualTo(expected)`, and all assertions must be awaited.

How do I migrate tests from xUnit to TUnit?

Replace [Fact]/[Theory] with [Test], [InlineData] with [Arguments], [MemberData] with [MethodData], Assert.Equal/True/Throws with await Assert.That(...) equivalents, and constructor/IDisposable or IClassFixture with [Before]/[After] lifecycle hooks.

Does TUnit support data-driven tests?

Yes, via [Arguments] for inline data, [MethodData] for method-based data, [ClassData] for class-based data, or custom sources implementing ITestDataSource.

Does TUnit run tests in parallel by default?

Yes, TUnit runs tests in parallel by default, unlike xUnit. You can use [NotInParallel] or [ParallelLimit<T>] to control this.

Full instructions (SKILL.md)

Source of truth, from github/awesome-copilot.


name: csharp-tunit description: 'Get best practices for TUnit unit testing, including data-driven tests'

TUnit Best Practices

Your goal is to help me write effective unit tests with TUnit, covering both standard and data-driven testing approaches.

Project Setup

  • Use a separate test project with naming convention [ProjectName].Tests
  • Reference TUnit package and TUnit.Assertions for fluent assertions
  • Create test classes that match the classes being tested (e.g., CalculatorTests for Calculator)
  • Use .NET SDK test commands: dotnet test for running tests
  • TUnit requires .NET 8.0 or higher

Test Structure

  • No test class attributes required (like xUnit/NUnit)
  • Use [Test] attribute for test methods (not [Fact] like xUnit)
  • Follow the Arrange-Act-Assert (AAA) pattern
  • Name tests using the pattern MethodName_Scenario_ExpectedBehavior
  • Use lifecycle hooks: [Before(Test)] for setup and [After(Test)] for teardown
  • Use [Before(Class)] and [After(Class)] for shared context between tests in a class
  • Use [Before(Assembly)] and [After(Assembly)] for shared context across test classes
  • TUnit supports advanced lifecycle hooks like [Before(TestSession)] and [After(TestSession)]

Standard Tests

  • Keep tests focused on a single behavior
  • Avoid testing multiple behaviors in one test method
  • Use TUnit's fluent assertion syntax with await Assert.That()
  • Include only the assertions needed to verify the test case
  • Make tests independent and idempotent (can run in any order)
  • Avoid test interdependencies (use [DependsOn] attribute if needed)

Data-Driven Tests

  • Use [Arguments] attribute for inline test data (equivalent to xUnit's [InlineData])
  • Use [MethodData] for method-based test data (equivalent to xUnit's [MemberData])
  • Use [ClassData] for class-based test data
  • Create custom data sources by implementing ITestDataSource
  • Use meaningful parameter names in data-driven tests
  • Multiple [Arguments] attributes can be applied to the same test method

Assertions

  • Use await Assert.That(value).IsEqualTo(expected) for value equality
  • Use await Assert.That(value).IsSameReferenceAs(expected) for reference equality
  • Use await Assert.That(value).IsTrue() or await Assert.That(value).IsFalse() for boolean conditions
  • Use await Assert.That(collection).Contains(item) or await Assert.That(collection).DoesNotContain(item) for collections
  • Use await Assert.That(value).Matches(pattern) for regex pattern matching
  • Use await Assert.That(action).Throws<TException>() or await Assert.That(asyncAction).ThrowsAsync<TException>() to test exceptions
  • Chain assertions with .And operator: await Assert.That(value).IsNotNull().And.IsEqualTo(expected)
  • Use .Or operator for alternative conditions: await Assert.That(value).IsEqualTo(1).Or.IsEqualTo(2)
  • Use .Within(tolerance) for DateTime and numeric comparisons with tolerance
  • All assertions are asynchronous and must be awaited

Advanced Features

  • Use [Repeat(n)] to repeat tests multiple times
  • Use [Retry(n)] for automatic retry on failure
  • Use [ParallelLimit<T>] to control parallel execution limits
  • Use [Skip("reason")] to skip tests conditionally
  • Use [DependsOn(nameof(OtherTest))] to create test dependencies
  • Use [Timeout(milliseconds)] to set test timeouts
  • Create custom attributes by extending TUnit's base attributes

Test Organization

  • Group tests by feature or component
  • Use [Category("CategoryName")] for test categorization
  • Use [DisplayName("Custom Test Name")] for custom test names
  • Consider using TestContext for test diagnostics and information
  • Use conditional attributes like custom [WindowsOnly] for platform-specific tests

Performance and Parallel Execution

  • TUnit runs tests in parallel by default (unlike xUnit which requires explicit configuration)
  • Use [NotInParallel] to disable parallel execution for specific tests
  • Use [ParallelLimit<T>] with custom limit classes to control concurrency
  • Tests within the same class run sequentially by default
  • Use [Repeat(n)] with [ParallelLimit<T>] for load testing scenarios

Migration from xUnit

  • Replace [Fact] with [Test]
  • Replace [Theory] with [Test] and use [Arguments] for data
  • Replace [InlineData] with [Arguments]
  • Replace [MemberData] with [MethodData]
  • Replace Assert.Equal with await Assert.That(actual).IsEqualTo(expected)
  • Replace Assert.True with await Assert.That(condition).IsTrue()
  • Replace Assert.Throws<T> with await Assert.That(action).Throws<T>()
  • Replace constructor/IDisposable with [Before(Test)]/[After(Test)]
  • Replace IClassFixture<T> with [Before(Class)]/[After(Class)]

Why TUnit over xUnit?

TUnit offers a modern, fast, and flexible testing experience with advanced features not present in xUnit, such as asynchronous assertions, more refined lifecycle hooks, and improved data-driven testing capabilities. TUnit's fluent assertions provide clearer and more expressive test validation, making it especially suitable for complex .NET projects.