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- .NET 8.0 SDK or higher
- A separate test project referencing TUnit and TUnit.Assertions packages
How to use csharp-tunit
- 1.Create a separate test project named [ProjectName].Tests targeting .NET 8.0 or higher
- 2.Reference the TUnit and TUnit.Assertions packages
- 3.Create test classes matching the classes under test (e.g., CalculatorTests)
- 4.Write test methods using [Test] and follow the Arrange-Act-Assert pattern, naming them MethodName_Scenario_ExpectedBehavior
- 5.Use [Before(Test)]/[After(Test)] or class/assembly-level hooks for setup and teardown
- 6.Write assertions using await Assert.That(...) fluent syntax
- 7.Add data-driven tests with [Arguments], [MethodData], or [ClassData] as needed
- 8.Apply advanced attributes like [Repeat], [Retry], [Skip], [DependsOn], or [Timeout] where relevant
Use cases
- 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
- .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
No. Unlike xUnit/NUnit, TUnit does not require a test class attribute; just use [Test] on test methods.
Assertions use a fluent, asynchronous syntax like `await Assert.That(value).IsEqualTo(expected)`, and all assertions must be awaited.
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.
Yes, via [Arguments] for inline data, [MethodData] for method-based data, [ClassData] for class-based data, or custom sources implementing ITestDataSource.
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.,
CalculatorTestsforCalculator) - Use .NET SDK test commands:
dotnet testfor 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()orawait Assert.That(value).IsFalse()for boolean conditions - Use
await Assert.That(collection).Contains(item)orawait 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>()orawait Assert.That(asyncAction).ThrowsAsync<TException>()to test exceptions - Chain assertions with
.Andoperator:await Assert.That(value).IsNotNull().And.IsEqualTo(expected) - Use
.Oroperator 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
TestContextfor 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.Equalwithawait Assert.That(actual).IsEqualTo(expected) - Replace
Assert.Truewithawait Assert.That(condition).IsTrue() - Replace
Assert.Throws<T>withawait 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.
Related skills
More from github/awesome-copilot and the wider catalog.

csharp-xunit
XUnit best practices for C# unit testing, including data-driven tests and test organization.

daily-prep
Prepare for tomorrow's meetings and tasks with calendar analysis, conflict detection, and productivity recommendations.

datanalysis-credit-risk
Credit risk data cleaning and variable screening pipeline for pre-loan modeling

dataverse-python-advanced-patterns
Generate production-ready Dataverse SDK Python code with advanced patterns, error handling, and optimization.

dataverse-python-production-code
Generate production-ready Python code for Dataverse SDK with error handling, retry logic, and best practices

dataverse-python-quickstart
Generate ready-to-use Python snippets for Microsoft Dataverse SDK setup, CRUD, bulk ops, and paging.