{"id":"a3116205-3201-4fd3-b272-a1d3fff83231","shortId":"gRZspJ","kind":"skill","title":"Csharp Tunit","tagline":"Awesome Copilot skill by Github","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"],"capabilities":["skill","source-github","category-awesome-copilot"],"categories":["awesome-copilot"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/github/awesome-copilot/csharp-tunit","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"install_from":"skills.sh"}},"qualityScore":"0.300","qualityRationale":"deterministic score 0.30 from registry signals: · indexed on skills.sh · published under github/awesome-copilot","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:v1","enrichmentVersion":1,"enrichedAt":"2026-04-22T09:40:13.887Z","embedding":null,"createdAt":"2026-04-18T20:26:10.211Z","updatedAt":"2026-04-22T09:40:13.887Z","lastSeenAt":"2026-04-22T09:40:13.887Z","tsv":"'1':373 '2':375 '8.0':78 'aaa':106 'across':151 'act':104 'action':342,589 'actual':574 'advanc':156,394,619 'altern':367 'and.isequalto':361 'appli':277 'approach':31 'argument':224,273,558,564 'arrang':103 'arrange-act-assert':102 'assembl':144,147 'assert':51,105,186,194,283,353,387,628,643 'assert.equal':570 'assert.that':190,286,295,304,309,317,323,331,341,346,358,370,573,581,588 'assert.throws':585 'assert.true':578 'asyncact':347 'asynchron':389,627 'attribut':86,92,216,225,274,443,449,483 'automat':408 'avoid':174,211 'await':189,285,294,303,308,316,322,330,340,345,357,369,393,572,580,587 'awesom':3 'base':240,253,448 'behavior':173,177 'best':9 'boolean':313 'calcul':64 'calculatortest':62 'capabl':639 'case':200 'categor':463 'categori':459 'category-awesome-copilot' 'categorynam':460 'chain':352 'class':54,58,85,130,133,141,153,252,523,531,602,604 'class-bas':251 'classdata':249 'clearer':645 'collect':318,324,328 'command':69 'comparison':383 'complex':656 'compon':457 'concurr':526 'condit':314,368,425,482,582 'configur':508 'consid':473 'constructor/idisposable':592 'contain':319 'context':136,150 'control':415,525 'convent':41 'copilot':4 'cover':23 'creat':52,256,431,441 'csharp':1 'custom':257,442,466,470,485,521 'data':28,220,229,242,255,258,269,560,636 'data-driven':27,219,268,635 'datetim':380 'default':502,535 'depend':433 'dependson':215,427 'diagnost':478 'disabl':512 'displaynam':465 'doesnotcontain':325 'dotnet':70 'driven':29,221,270,637 'e.g':61 'effect':18 'equal':292,301 'equival':230,243 'especi':653 'except':351 'execut':417,495,514 'expect':289,298,362,576 'expectedbehavior':115 'experi':617 'explicit':507 'express':648 'extend':445 'fact':97,549 'failur':411 'fast':613 'featur':395,455,620 'flexibl':615 'fluent':50,185,642 'focus':169 'follow':100 'github':7 'goal':12 'group':452 'help':15 'higher':80 'hook':118,158,632 'iclassfixtur':599 'idempot':205 'implement':261 'improv':634 'includ':191 'independ':203 'inform':480 'inlin':227 'inlinedata':234,562 'interdepend':213 'isequalto':288,372,575 'isfals':311 'isnotnul':360 'issamereferencea':297 'istru':306,583 'item':320,326 'itestdatasourc':262 'keep':167 'lifecycl':117,157,631 'like':88,98,159,484 'limit':418,522 'load':542 'make':201,651 'match':56,333,338 'meaning':264 'memberdata':247,566 'method':95,181,239,282 'method-bas':238 'methoddata':236,568 'methodnam':113 'migrat':545 'millisecond':436 'modern':612 'multipl':176,272,402 'must':391 'n':398,406,538 'name':40,108,266,468,472 'nameof':428 'need':195,218 'net':66,77,657 'notinparallel':510 'numer':382 'offer':610 'one':179 'oper':356,365 'or.isequalto':374 'order':210 'organ':451 'othertest':429 'packag':46 'parallel':416,494,500,513 'parallellimit':413,519,540 'paramet':265 'pattern':107,112,334,337 'perform':492 'platform':489 'platform-specif':488 'practic':10 'present':622 'project':32,38,658 'projectnam':42 'provid':644 'reason':421 'refer':44,300 'refin':630 'regex':336 'repeat':397,400,537 'replac':548,552,561,565,569,577,584,591,598 'requir':76,87,506 'retri':405,409 'run':73,207,497,532 'scenario':114,544 'sdk':67 'separ':36 'sequenti':533 'set':438 'setup':33,122 'share':135,149 'singl':172 'skill':5 'skip':420,423 'sourc':259 'source-github' 'specif':490,516 'standard':25,165 'structur':82 'suitabl':654 'support':155 'syntax':187 'teardown':127 'test':20,30,37,43,53,60,68,71,74,81,84,91,94,109,120,125,138,152,166,168,175,180,199,202,212,222,228,241,254,271,281,350,401,424,432,439,450,453,462,467,471,477,491,498,517,527,543,551,555,595,597,616,638,649 'testcontext':475 'testsess':161,164 'theori':553 'throw':343,590 'throwsasync':348 'time':403 'timeout':435,440 'toler':378,385 'tunit':2,8,22,45,75,154,183,446,496,606,609,640 'tunit.assertions':48 'unit':19 'unlik':503 'use':34,65,90,110,116,128,142,182,214,223,235,248,263,284,293,302,315,329,339,363,376,396,404,412,419,426,434,458,464,474,481,509,518,536,557 'valid':650 'valu':287,291,296,305,310,332,359,371 'verifi':197 'windowson':486 'within':377,528 'write':17 'xunit':99,232,245,504,547,608,624 'xunit/nunit':89","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-04-22T06:52:18.994Z"},{"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-04-22T09:40:13.887Z"}],"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","source":"skills_sh","category":"awesome-copilot","skills_sh_url":"https://skills.sh/github/awesome-copilot/csharp-tunit"},"updatedAt":"2026-04-22T09:40:13.887Z"}}