{"id":"a3116205-3201-4fd3-b272-a1d3fff83231","shortId":"gRZspJ","kind":"skill","title":"csharp-tunit","tagline":"Get best practices for TUnit unit testing, including data-driven tests","description":"# TUnit Best Practices\n\nYour goal is to help me write effective unit tests with TUnit, covering both standard and data-driven testing approaches.\n\n## Project Setup\n\n- Use a separate test project with naming convention `[ProjectName].Tests`\n- Reference TUnit package and TUnit.Assertions for fluent assertions\n- Create test classes that match the classes being tested (e.g., `CalculatorTests` for `Calculator`)\n- Use .NET SDK test commands: `dotnet test` for running tests\n- TUnit requires .NET 8.0 or higher\n\n## Test Structure\n\n- No test class attributes required (like xUnit/NUnit)\n- Use `[Test]` attribute for test methods (not `[Fact]` like xUnit)\n- Follow the Arrange-Act-Assert (AAA) pattern\n- Name tests using the pattern `MethodName_Scenario_ExpectedBehavior`\n- Use lifecycle hooks: `[Before(Test)]` for setup and `[After(Test)]` for teardown\n- Use `[Before(Class)]` and `[After(Class)]` for shared context between tests in a class\n- Use `[Before(Assembly)]` and `[After(Assembly)]` for shared context across test classes\n- TUnit supports advanced lifecycle hooks like `[Before(TestSession)]` and `[After(TestSession)]`\n\n## Standard Tests\n\n- Keep tests focused on a single behavior\n- Avoid testing multiple behaviors in one test method\n- Use TUnit's fluent assertion syntax with `await Assert.That()`\n- Include only the assertions needed to verify the test case\n- Make tests independent and idempotent (can run in any order)\n- Avoid test interdependencies (use `[DependsOn]` attribute if needed)\n\n## Data-Driven Tests\n\n- Use `[Arguments]` attribute for inline test data (equivalent to xUnit's `[InlineData]`)\n- Use `[MethodData]` for method-based test data (equivalent to xUnit's `[MemberData]`)\n- Use `[ClassData]` for class-based test data\n- Create custom data sources by implementing `ITestDataSource`\n- Use meaningful parameter names in data-driven tests\n- Multiple `[Arguments]` attributes can be applied to the same test method\n\n## Assertions\n\n- Use `await Assert.That(value).IsEqualTo(expected)` for value equality\n- Use `await Assert.That(value).IsSameReferenceAs(expected)` for reference equality\n- Use `await Assert.That(value).IsTrue()` or `await Assert.That(value).IsFalse()` for boolean conditions\n- Use `await Assert.That(collection).Contains(item)` or `await Assert.That(collection).DoesNotContain(item)` for collections\n- Use `await Assert.That(value).Matches(pattern)` for regex pattern matching\n- Use `await Assert.That(action).Throws<TException>()` or `await Assert.That(asyncAction).ThrowsAsync<TException>()` to test exceptions\n- Chain assertions with `.And` operator: `await Assert.That(value).IsNotNull().And.IsEqualTo(expected)`\n- Use `.Or` operator for alternative conditions: `await Assert.That(value).IsEqualTo(1).Or.IsEqualTo(2)`\n- Use `.Within(tolerance)` for DateTime and numeric comparisons with tolerance\n- All assertions are asynchronous and must be awaited\n\n## Advanced Features\n\n- Use `[Repeat(n)]` to repeat tests multiple times\n- Use `[Retry(n)]` for automatic retry on failure\n- Use `[ParallelLimit<T>]` to control parallel execution limits\n- Use `[Skip(\"reason\")]` to skip tests conditionally\n- Use `[DependsOn(nameof(OtherTest))]` to create test dependencies\n- Use `[Timeout(milliseconds)]` to set test timeouts\n- Create custom attributes by extending TUnit's base attributes\n\n## Test Organization\n\n- Group tests by feature or component\n- Use `[Category(\"CategoryName\")]` for test categorization\n- Use `[DisplayName(\"Custom Test Name\")]` for custom test names\n- Consider using `TestContext` for test diagnostics and information\n- Use conditional attributes like custom `[WindowsOnly]` for platform-specific tests\n\n## Performance and Parallel Execution\n\n- TUnit runs tests in parallel by default (unlike xUnit which requires explicit configuration)\n- Use `[NotInParallel]` to disable parallel execution for specific tests\n- Use `[ParallelLimit<T>]` with custom limit classes to control concurrency\n- Tests within the same class run sequentially by default\n- Use `[Repeat(n)]` with `[ParallelLimit<T>]` for load testing scenarios\n\n## Migration from xUnit\n\n- Replace `[Fact]` with `[Test]`\n- Replace `[Theory]` with `[Test]` and use `[Arguments]` for data\n- Replace `[InlineData]` with `[Arguments]`\n- Replace `[MemberData]` with `[MethodData]`\n- Replace `Assert.Equal` with `await Assert.That(actual).IsEqualTo(expected)`\n- Replace `Assert.True` with `await Assert.That(condition).IsTrue()`\n- Replace `Assert.Throws<T>` with `await Assert.That(action).Throws<T>()`\n- Replace constructor/IDisposable with `[Before(Test)]`/`[After(Test)]`\n- Replace `IClassFixture<T>` with `[Before(Class)]`/`[After(Class)]`\n\n**Why TUnit over xUnit?**\n\nTUnit 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.","tags":["csharp","tunit","awesome","copilot","github","agent-skills","agents","custom-agents","github-copilot","hacktoberfest","prompt-engineering"],"capabilities":["skill","source-github","skill-csharp-tunit","topic-agent-skills","topic-agents","topic-awesome","topic-custom-agents","topic-github-copilot","topic-hacktoberfest","topic-prompt-engineering"],"categories":["awesome-copilot"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/github/awesome-copilot/csharp-tunit","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add github/awesome-copilot","source_repo":"https://github.com/github/awesome-copilot","install_from":"skills.sh"}},"qualityScore":"0.700","qualityRationale":"deterministic score 0.70 from registry signals: · indexed on github topic:agent-skills · 33270 github stars · SKILL.md body (5,030 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T18:52:09.299Z","embedding":null,"createdAt":"2026-04-18T20:26:10.211Z","updatedAt":"2026-05-18T18:52:09.299Z","lastSeenAt":"2026-05-18T18:52:09.299Z","tsv":"'1':381 '2':383 '8.0':86 'aaa':114 'across':159 'act':112 'action':350,597 'actual':582 'advanc':164,402,627 'altern':375 'and.isequalto':369 'appli':285 'approach':39 'argument':232,281,566,572 'arrang':111 'arrange-act-assert':110 'assembl':152,155 'assert':59,113,194,202,291,361,395,636,651 'assert.equal':578 'assert.that':198,294,303,312,317,325,331,339,349,354,366,378,581,589,596 'assert.throws':593 'assert.true':586 'asyncact':355 'asynchron':397,635 'attribut':94,100,224,233,282,451,457,491 'automat':416 'avoid':182,219 'await':197,293,302,311,316,324,330,338,348,353,365,377,401,580,588,595 'base':248,261,456 'behavior':181,185 'best':5,17 'boolean':321 'calcul':72 'calculatortest':70 'capabl':647 'case':208 'categor':471 'categori':467 'categorynam':468 'chain':360 'class':62,66,93,138,141,149,161,260,531,539,610,612 'class-bas':259 'classdata':257 'clearer':653 'collect':326,332,336 'command':77 'comparison':391 'complex':664 'compon':465 'concurr':534 'condit':322,376,433,490,590 'configur':516 'consid':481 'constructor/idisposable':600 'contain':327 'context':144,158 'control':423,533 'convent':49 'cover':31 'creat':60,264,439,449 'csharp':2 'csharp-tunit':1 'custom':265,450,474,478,493,529 'data':13,36,228,237,250,263,266,277,568,644 'data-driven':12,35,227,276,643 'datetim':388 'default':510,543 'depend':441 'dependson':223,435 'diagnost':486 'disabl':520 'displaynam':473 'doesnotcontain':333 'dotnet':78 'driven':14,37,229,278,645 'e.g':69 'effect':26 'equal':300,309 'equival':238,251 'especi':661 'except':359 'execut':425,503,522 'expect':297,306,370,584 'expectedbehavior':123 'experi':625 'explicit':515 'express':656 'extend':453 'fact':105,557 'failur':419 'fast':621 'featur':403,463,628 'flexibl':623 'fluent':58,193,650 'focus':177 'follow':108 'get':4 'goal':20 'group':460 'help':23 'higher':88 'hook':126,166,640 'iclassfixtur':607 'idempot':213 'implement':269 'improv':642 'includ':11,199 'independ':211 'inform':488 'inlin':235 'inlinedata':242,570 'interdepend':221 'isequalto':296,380,583 'isfals':319 'isnotnul':368 'issamereferencea':305 'istru':314,591 'item':328,334 'itestdatasourc':270 'keep':175 'lifecycl':125,165,639 'like':96,106,167,492 'limit':426,530 'load':550 'make':209,659 'match':64,341,346 'meaning':272 'memberdata':255,574 'method':103,189,247,290 'method-bas':246 'methoddata':244,576 'methodnam':121 'migrat':553 'millisecond':444 'modern':620 'multipl':184,280,410 'must':399 'n':406,414,546 'name':48,116,274,476,480 'nameof':436 'need':203,226 'net':74,85,665 'notinparallel':518 'numer':390 'offer':618 'one':187 'oper':364,373 'or.isequalto':382 'order':218 'organ':459 'othertest':437 'packag':54 'parallel':424,502,508,521 'parallellimit':421,527,548 'paramet':273 'pattern':115,120,342,345 'perform':500 'platform':497 'platform-specif':496 'practic':6,18 'present':630 'project':40,46,666 'projectnam':50 'provid':652 'reason':429 'refer':52,308 'refin':638 'regex':344 'repeat':405,408,545 'replac':556,560,569,573,577,585,592,599,606 'requir':84,95,514 'retri':413,417 'run':81,215,505,540 'scenario':122,552 'sdk':75 'separ':44 'sequenti':541 'set':446 'setup':41,130 'share':143,157 'singl':180 'skill' 'skill-csharp-tunit' 'skip':428,431 'sourc':267 'source-github' 'specif':498,524 'standard':33,173 'structur':90 'suitabl':662 'support':163 'syntax':195 'teardown':135 'test':10,15,28,38,45,51,61,68,76,79,82,89,92,99,102,117,128,133,146,160,174,176,183,188,207,210,220,230,236,249,262,279,289,358,409,432,440,447,458,461,470,475,479,485,499,506,525,535,551,559,563,603,605,624,646,657 'testcontext':483 'testsess':169,172 'theori':561 'throw':351,598 'throwsasync':356 'time':411 'timeout':443,448 'toler':386,393 'topic-agent-skills' 'topic-agents' 'topic-awesome' 'topic-custom-agents' 'topic-github-copilot' 'topic-hacktoberfest' 'topic-prompt-engineering' 'tunit':3,8,16,30,53,83,162,191,454,504,614,617,648 'tunit.assertions':56 'unit':9,27 'unlik':511 'use':42,73,98,118,124,136,150,190,222,231,243,256,271,292,301,310,323,337,347,371,384,404,412,420,427,434,442,466,472,482,489,517,526,544,565 'valid':658 'valu':295,299,304,313,318,340,367,379 'verifi':205 'windowson':494 'within':385,536 'write':25 'xunit':107,240,253,512,555,616,632 'xunit/nunit':97","prices":[{"id":"30badfaf-ef4e-4d67-bc18-751a0852d65f","listingId":"a3116205-3201-4fd3-b272-a1d3fff83231","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"github","category":"awesome-copilot","install_from":"skills.sh"},"createdAt":"2026-04-18T20:26:10.211Z"}],"sources":[{"listingId":"a3116205-3201-4fd3-b272-a1d3fff83231","source":"github","sourceId":"github/awesome-copilot/csharp-tunit","sourceUrl":"https://github.com/github/awesome-copilot/tree/main/skills/csharp-tunit","isPrimary":false,"firstSeenAt":"2026-04-18T21:49:02.187Z","lastSeenAt":"2026-05-18T18:52:09.299Z"},{"listingId":"a3116205-3201-4fd3-b272-a1d3fff83231","source":"skills_sh","sourceId":"github/awesome-copilot/csharp-tunit","sourceUrl":"https://skills.sh/github/awesome-copilot/csharp-tunit","isPrimary":true,"firstSeenAt":"2026-04-18T20:26:10.211Z","lastSeenAt":"2026-05-07T22:40:18.883Z"}],"details":{"listingId":"a3116205-3201-4fd3-b272-a1d3fff83231","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"github","slug":"csharp-tunit","github":{"repo":"github/awesome-copilot","stars":33270,"topics":["agent-skills","agents","ai","awesome","custom-agents","github-copilot","hacktoberfest","prompt-engineering"],"license":"mit","html_url":"https://github.com/github/awesome-copilot","pushed_at":"2026-05-18T01:26:59Z","description":"Community-contributed instructions, agents, skills, and configurations to help you make the most of GitHub Copilot.","skill_md_sha":"c972ebe1fd0db54f8ed66ad04cd2c4b244db1383","skill_md_path":"skills/csharp-tunit/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/github/awesome-copilot/tree/main/skills/csharp-tunit"},"layout":"multi","source":"github","category":"awesome-copilot","frontmatter":{"name":"csharp-tunit","description":"Get best practices for TUnit unit testing, including data-driven tests"},"skills_sh_url":"https://skills.sh/github/awesome-copilot/csharp-tunit"},"updatedAt":"2026-05-18T18:52:09.299Z"}}