{"id":"9b140ee1-7af4-458f-aa98-0a5018a9bdb1","shortId":"Vv68n5","kind":"skill","title":"csharp-mstest","tagline":"Get best practices for MSTest 3.x/4.x unit testing, including modern assertion APIs and data-driven tests","description":"# MSTest Best Practices (MSTest 3.x/4.x)\n\nYour goal is to help me write effective unit tests with modern MSTest, using current APIs and best practices.\n\n## Project Setup\n\n- Use a separate test project with naming convention `[ProjectName].Tests`\n- Reference MSTest 3.x+ NuGet packages (includes analyzers)\n- Consider using MSTest.Sdk for simplified project setup\n- Run tests with `dotnet test`\n\n## Test Class Structure\n\n- Use `[TestClass]` attribute for test classes\n- **Seal test classes by default** for performance and design clarity\n- Use `[TestMethod]` for test methods (prefer over `[DataTestMethod]`)\n- Follow Arrange-Act-Assert (AAA) pattern\n- Name tests using pattern `MethodName_Scenario_ExpectedBehavior`\n\n```csharp\n[TestClass]\npublic sealed class CalculatorTests\n{\n    [TestMethod]\n    public void Add_TwoPositiveNumbers_ReturnsSum()\n    {\n        // Arrange\n        var calculator = new Calculator();\n\n        // Act\n        var result = calculator.Add(2, 3);\n\n        // Assert\n        Assert.AreEqual(5, result);\n    }\n}\n```\n\n## Test Lifecycle\n\n- **Prefer constructors over `[TestInitialize]`** - enables `readonly` fields and follows standard C# patterns\n- Use `[TestCleanup]` for cleanup that must run even if test fails\n- Combine constructor with async `[TestInitialize]` when async setup is needed\n\n```csharp\n[TestClass]\npublic sealed class ServiceTests\n{\n    private readonly MyService _service;  // readonly enabled by constructor\n\n    public ServiceTests()\n    {\n        _service = new MyService();\n    }\n\n    [TestInitialize]\n    public async Task InitAsync()\n    {\n        // Use for async initialization only\n        await _service.WarmupAsync();\n    }\n\n    [TestCleanup]\n    public void Cleanup() => _service.Reset();\n}\n```\n\n### Execution Order\n\n1. **Assembly Initialization** - `[AssemblyInitialize]` (once per test assembly)\n2. **Class Initialization** - `[ClassInitialize]` (once per test class)\n3. **Test Initialization** (for every test method):\n   1. Constructor\n   2. Set `TestContext` property\n   3. `[TestInitialize]`\n4. **Test Execution** - test method runs\n5. **Test Cleanup** (for every test method):\n   1. `[TestCleanup]`\n   2. `DisposeAsync` (if implemented)\n   3. `Dispose` (if implemented)\n6. **Class Cleanup** - `[ClassCleanup]` (once per test class)\n7. **Assembly Cleanup** - `[AssemblyCleanup]` (once per test assembly)\n\n## Modern Assertion APIs\n\nMSTest provides three assertion classes: `Assert`, `StringAssert`, and `CollectionAssert`.\n\n### Assert Class - Core Assertions\n\n```csharp\n// Equality\nAssert.AreEqual(expected, actual);\nAssert.AreNotEqual(notExpected, actual);\nAssert.AreSame(expectedObject, actualObject);      // Reference equality\nAssert.AreNotSame(notExpectedObject, actualObject);\n\n// Null checks\nAssert.IsNull(value);\nAssert.IsNotNull(value);\n\n// Boolean\nAssert.IsTrue(condition);\nAssert.IsFalse(condition);\n\n// Fail/Inconclusive\nAssert.Fail(\"Test failed due to...\");\nAssert.Inconclusive(\"Test cannot be completed because...\");\n```\n\n### Exception Testing (Prefer over `[ExpectedException]`)\n\n```csharp\n// Assert.Throws - matches TException or derived types\nvar ex = Assert.Throws<ArgumentException>(() => Method(null));\nAssert.AreEqual(\"Value cannot be null.\", ex.Message);\n\n// Assert.ThrowsExactly - matches exact type only\nvar ex = Assert.ThrowsExactly<InvalidOperationException>(() => Method());\n\n// Async versions\nvar ex = await Assert.ThrowsAsync<HttpRequestException>(async () => await client.GetAsync(url));\nvar ex = await Assert.ThrowsExactlyAsync<InvalidOperationException>(async () => await Method());\n```\n\n### Collection Assertions (Assert class)\n\n```csharp\nAssert.Contains(expectedItem, collection);\nAssert.DoesNotContain(unexpectedItem, collection);\nAssert.ContainsSingle(collection);  // exactly one element\nAssert.HasCount(5, collection);\nAssert.IsEmpty(collection);\nAssert.IsNotEmpty(collection);\n```\n\n### String Assertions (Assert class)\n\n```csharp\nAssert.Contains(\"expected\", actualString);\nAssert.StartsWith(\"prefix\", actualString);\nAssert.EndsWith(\"suffix\", actualString);\nAssert.DoesNotStartWith(\"prefix\", actualString);\nAssert.DoesNotEndWith(\"suffix\", actualString);\nAssert.MatchesRegex(@\"\\d{3}-\\d{4}\", phoneNumber);\nAssert.DoesNotMatchRegex(@\"\\d+\", textOnly);\n```\n\n### Comparison Assertions\n\n```csharp\nAssert.IsGreaterThan(lowerBound, actual);\nAssert.IsGreaterThanOrEqualTo(lowerBound, actual);\nAssert.IsLessThan(upperBound, actual);\nAssert.IsLessThanOrEqualTo(upperBound, actual);\nAssert.IsInRange(actual, low, high);\nAssert.IsPositive(number);\nAssert.IsNegative(number);\n```\n\n### Type Assertions\n\n```csharp\n// MSTest 3.x - uses out parameter\nAssert.IsInstanceOfType<MyClass>(obj, out var typed);\ntyped.DoSomething();\n\n// MSTest 4.x - returns typed result directly\nvar typed = Assert.IsInstanceOfType<MyClass>(obj);\ntyped.DoSomething();\n\nAssert.IsNotInstanceOfType<WrongType>(obj);\n```\n\n### Assert.That (MSTest 4.0+)\n\n```csharp\nAssert.That(result.Count > 0);  // Auto-captures expression in failure message\n```\n\n### StringAssert Class\n\n> **Note:** Prefer `Assert` class equivalents when available (e.g., `Assert.Contains(\"expected\", actual)` over `StringAssert.Contains(actual, \"expected\")`).\n\n```csharp\nStringAssert.Contains(actualString, \"expected\");\nStringAssert.StartsWith(actualString, \"prefix\");\nStringAssert.EndsWith(actualString, \"suffix\");\nStringAssert.Matches(actualString, new Regex(@\"\\d{3}-\\d{4}\"));\nStringAssert.DoesNotMatch(actualString, new Regex(@\"\\d+\"));\n```\n\n### CollectionAssert Class\n\n> **Note:** Prefer `Assert` class equivalents when available (e.g., `Assert.Contains`).\n\n```csharp\n// Containment\nCollectionAssert.Contains(collection, expectedItem);\nCollectionAssert.DoesNotContain(collection, unexpectedItem);\n\n// Equality (same elements, same order)\nCollectionAssert.AreEqual(expectedCollection, actualCollection);\nCollectionAssert.AreNotEqual(unexpectedCollection, actualCollection);\n\n// Equivalence (same elements, any order)\nCollectionAssert.AreEquivalent(expectedCollection, actualCollection);\nCollectionAssert.AreNotEquivalent(unexpectedCollection, actualCollection);\n\n// Subset checks\nCollectionAssert.IsSubsetOf(subset, superset);\nCollectionAssert.IsNotSubsetOf(notSubset, collection);\n\n// Element validation\nCollectionAssert.AllItemsAreInstancesOfType(collection, typeof(MyClass));\nCollectionAssert.AllItemsAreNotNull(collection);\nCollectionAssert.AllItemsAreUnique(collection);\n```\n\n## Data-Driven Tests\n\n### DataRow\n\n```csharp\n[TestMethod]\n[DataRow(1, 2, 3)]\n[DataRow(0, 0, 0, DisplayName = \"Zeros\")]\n[DataRow(-1, 1, 0, IgnoreMessage = \"Known issue #123\")]  // MSTest 3.8+\npublic void Add_ReturnsSum(int a, int b, int expected)\n{\n    Assert.AreEqual(expected, Calculator.Add(a, b));\n}\n```\n\n### DynamicData\n\nThe data source can return any of the following types:\n\n- `IEnumerable<(T1, T2, ...)>` (ValueTuple) - **preferred**, provides type safety (MSTest 3.7+)\n- `IEnumerable<Tuple<T1, T2, ...>>` - provides type safety\n- `IEnumerable<TestDataRow>` - provides type safety plus control over test metadata (display name, categories)\n- `IEnumerable<object[]>` - **least preferred**, no type safety\n\n> **Note:** When creating new test data methods, prefer `ValueTuple` or `TestDataRow` over `IEnumerable<object[]>`. The `object[]` approach provides no compile-time type checking and can lead to runtime errors from type mismatches.\n\n```csharp\n[TestMethod]\n[DynamicData(nameof(TestData))]\npublic void DynamicTest(int a, int b, int expected)\n{\n    Assert.AreEqual(expected, Calculator.Add(a, b));\n}\n\n// ValueTuple - preferred (MSTest 3.7+)\npublic static IEnumerable<(int a, int b, int expected)> TestData =>\n[\n    (1, 2, 3),\n    (0, 0, 0),\n];\n\n// TestDataRow - when you need custom display names or metadata\npublic static IEnumerable<TestDataRow<(int a, int b, int expected)>> TestDataWithMetadata =>\n[\n    new((1, 2, 3)) { DisplayName = \"Positive numbers\" },\n    new((0, 0, 0)) { DisplayName = \"Zeros\" },\n    new((-1, 1, 0)) { DisplayName = \"Mixed signs\", IgnoreMessage = \"Known issue #123\" },\n];\n\n// IEnumerable<object[]> - avoid for new code (no type safety)\npublic static IEnumerable<object[]> LegacyTestData =>\n[\n    [1, 2, 3],\n    [0, 0, 0],\n];\n```\n\n## TestContext\n\nThe `TestContext` class provides test run information, cancellation support, and output methods.\nSee [TestContext documentation](https://learn.microsoft.com/dotnet/core/testing/unit-testing-mstest-writing-tests-testcontext) for complete reference.\n\n### Accessing TestContext\n\n```csharp\n// Property (MSTest suppresses CS8618 - don't use nullable or = null!)\npublic TestContext TestContext { get; set; }\n\n// Constructor injection (MSTest 3.6+) - preferred for immutability\n[TestClass]\npublic sealed class MyTests\n{\n    private readonly TestContext _testContext;\n\n    public MyTests(TestContext testContext)\n    {\n        _testContext = testContext;\n    }\n}\n\n// Static methods receive it as parameter\n[ClassInitialize]\npublic static void ClassInit(TestContext context) { }\n\n// Optional for cleanup methods (MSTest 3.6+)\n[ClassCleanup]\npublic static void ClassCleanup(TestContext context) { }\n\n[AssemblyCleanup]\npublic static void AssemblyCleanup(TestContext context) { }\n```\n\n### Cancellation Token\n\nAlways use `TestContext.CancellationToken` for cooperative cancellation with `[Timeout]`:\n\n```csharp\n[TestMethod]\n[Timeout(5000)]\npublic async Task LongRunningTest()\n{\n    await _httpClient.GetAsync(url, TestContext.CancellationToken);\n}\n```\n\n### Test Run Properties\n\n```csharp\nTestContext.TestName              // Current test method name\nTestContext.TestDisplayName       // Display name (3.7+)\nTestContext.CurrentTestOutcome    // Pass/Fail/InProgress\nTestContext.TestData              // Parameterized test data (3.7+, in TestInitialize/Cleanup)\nTestContext.TestException         // Exception if test failed (3.7+, in TestCleanup)\nTestContext.DeploymentDirectory   // Directory with deployment items\n```\n\n### Output and Result Files\n\n```csharp\n// Write to test output (useful for debugging)\nTestContext.WriteLine(\"Processing item {0}\", itemId);\n\n// Attach files to test results (logs, screenshots)\nTestContext.AddResultFile(screenshotPath);\n\n// Store/retrieve data across test methods\nTestContext.Properties[\"SharedKey\"] = computedValue;\n```\n\n## Advanced Features\n\n### Retry for Flaky Tests (MSTest 3.9+)\n\n```csharp\n[TestMethod]\n[Retry(3)]\npublic void FlakyTest() { }\n```\n\n### Conditional Execution (MSTest 3.10+)\n\nSkip or run tests based on OS or CI environment:\n\n```csharp\n// OS-specific tests\n[TestMethod]\n[OSCondition(OperatingSystems.Windows)]\npublic void WindowsOnlyTest() { }\n\n[TestMethod]\n[OSCondition(OperatingSystems.Linux | OperatingSystems.MacOS)]\npublic void UnixOnlyTest() { }\n\n[TestMethod]\n[OSCondition(ConditionMode.Exclude, OperatingSystems.Windows)]\npublic void SkipOnWindowsTest() { }\n\n// CI environment tests\n[TestMethod]\n[CICondition]  // Runs only in CI (default: ConditionMode.Include)\npublic void CIOnlyTest() { }\n\n[TestMethod]\n[CICondition(ConditionMode.Exclude)]  // Skips in CI, runs locally\npublic void LocalOnlyTest() { }\n```\n\n### Parallelization\n\n```csharp\n// Assembly level\n[assembly: Parallelize(Workers = 4, Scope = ExecutionScope.MethodLevel)]\n\n// Disable for specific class\n[TestClass]\n[DoNotParallelize]\npublic sealed class SequentialTests { }\n```\n\n### Work Item Traceability (MSTest 3.8+)\n\nLink tests to work items for traceability in test reports:\n\n```csharp\n// Azure DevOps work items\n[TestMethod]\n[WorkItem(12345)]  // Links to work item #12345\npublic void Feature_Scenario_ExpectedBehavior() { }\n\n// Multiple work items\n[TestMethod]\n[WorkItem(12345)]\n[WorkItem(67890)]\npublic void Feature_CoversMultipleRequirements() { }\n\n// GitHub issues (MSTest 3.8+)\n[TestMethod]\n[GitHubWorkItem(\"https://github.com/owner/repo/issues/42\")]\npublic void BugFix_Issue42_IsResolved() { }\n```\n\nWork item associations appear in test results and can be used for:\n- Tracing test coverage to requirements\n- Linking bug fixes to regression tests\n- Generating traceability reports in CI/CD pipelines\n\n## Common Mistakes to Avoid\n\n```csharp\n// ❌ Wrong argument order\nAssert.AreEqual(actual, expected);\n// ✅ Correct\nAssert.AreEqual(expected, actual);\n\n// ❌ Using ExpectedException (obsolete)\n[ExpectedException(typeof(ArgumentException))]\n// ✅ Use Assert.Throws\nAssert.Throws<ArgumentException>(() => Method());\n\n// ❌ Using LINQ Single() - unclear exception\nvar item = items.Single();\n// ✅ Use ContainsSingle - better failure message\nvar item = Assert.ContainsSingle(items);\n\n// ❌ Hard cast - unclear exception\nvar handler = (MyHandler)result;\n// ✅ Type assertion - shows actual type on failure\nvar handler = Assert.IsInstanceOfType<MyHandler>(result);\n\n// ❌ Ignoring cancellation token\nawait client.GetAsync(url, CancellationToken.None);\n// ✅ Flow test cancellation\nawait client.GetAsync(url, TestContext.CancellationToken);\n\n// ❌ Making TestContext nullable - leads to unnecessary null checks\npublic TestContext? TestContext { get; set; }\n// ❌ Using null! - MSTest already suppresses CS8618 for this property\npublic TestContext TestContext { get; set; } = null!;\n// ✅ Declare without nullable or initializer - MSTest handles the warning\npublic TestContext TestContext { get; set; }\n```\n\n## Test Organization\n\n- Group tests by feature or component\n- Use `[TestCategory(\"Category\")]` for filtering\n- Use `[TestProperty(\"Name\", \"Value\")]` for custom metadata (e.g., `[TestProperty(\"Bug\", \"12345\")]`)\n- Use `[Priority(1)]` for critical tests\n- Enable relevant MSTest analyzers (MSTEST0020 for constructor preference)\n\n## Mocking and Isolation\n\n- Use Moq or NSubstitute for mocking dependencies\n- Use interfaces to facilitate mocking\n- Mock dependencies to isolate units under test","tags":["csharp","mstest","awesome","copilot","github","agent-skills","agents","custom-agents","github-copilot","hacktoberfest","prompt-engineering"],"capabilities":["skill","source-github","skill-csharp-mstest","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-mstest","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 (13,679 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.147Z","embedding":null,"createdAt":"2026-04-18T20:26:07.784Z","updatedAt":"2026-05-18T18:52:09.147Z","lastSeenAt":"2026-05-18T18:52:09.147Z","tsv":"'-1':629,806 '/dotnet/core/testing/unit-testing-mstest-writing-tests-testcontext)':854 '/owner/repo/issues/42':1174 '0':504,623,624,625,631,769,770,771,800,801,802,808,833,834,835,1003 '1':220,243,264,619,630,766,793,807,830,1352 '123':635,815 '12345':1143,1148,1159,1349 '2':141,228,245,266,620,767,794,831 '3':9,26,61,142,236,249,270,439,473,544,621,768,795,832,1033 '3.10':1040 '3.6':879,916 '3.7':673,755,965,972,980 '3.8':637,1125,1169 '3.9':1029 '4':251,441,485,546,1108 '4.0':500 '5':145,257,411 '5000':944 '6':274 '67890':1161 '7':282 'aaa':111 'access':858 'across':1016 'act':109,137 'actual':310,313,451,454,457,460,462,524,527,1218,1223,1262 'actualcollect':578,581,589,592 'actualobject':316,321 'actualstr':424,427,430,433,436,531,534,537,540,548 'add':129,640 'advanc':1022 'alreadi':1300 'alway':933 'analyz':66,1359 'api':16,43,292 'appear':1183 'approach':716 'argument':1215 'argumentexcept':1229 'arrang':108,132 'arrange-act-assert':107 'assembl':221,227,283,289,1103,1105 'assemblycleanup':285,924,928 'assemblyiniti':223 'assert':15,110,143,291,296,298,302,305,395,396,418,419,447,470,516,556,1260 'assert.areequal':144,308,362,648,747,1217,1221 'assert.arenotequal':311 'assert.arenotsame':319 'assert.aresame':314 'assert.contains':399,422,522,562 'assert.containssingle':405,1249 'assert.doesnotcontain':402 'assert.doesnotendwith':434 'assert.doesnotmatchregex':443 'assert.doesnotstartwith':431 'assert.endswith':428 'assert.fail':334 'assert.hascount':410 'assert.inconclusive':339 'assert.isempty':413 'assert.isfalse':331 'assert.isgreaterthan':449 'assert.isgreaterthanorequalto':452 'assert.isinrange':461 'assert.isinstanceoftype':478,493,1268 'assert.islessthan':455 'assert.islessthanorequalto':458 'assert.isnegative':467 'assert.isnotempty':415 'assert.isnotinstanceoftype':496 'assert.isnotnull':326 'assert.isnull':324 'assert.ispositive':465 'assert.istrue':329 'assert.matchesregex':437 'assert.startswith':425 'assert.that':498,502 'assert.throws':351,359,1231,1232 'assert.throwsasync':382 'assert.throwsexactly':368,375 'assert.throwsexactlyasync':390 'associ':1182 'async':175,178,203,208,377,383,391,946 'attach':1005 'attribut':84 'auto':506 'auto-captur':505 'avail':520,560 'avoid':818,1212 'await':211,381,384,389,392,949,1273,1280 'azur':1137 'b':645,652,744,751,762,788 'base':1045 'best':5,23,45 'better':1244 'boolean':328 'bug':1198,1348 'bugfix':1177 'c':159 'calcul':134,136 'calculator.add':140,650,749 'calculatortest':125 'cancel':844,931,938,1271,1279 'cancellationtoken.none':1276 'cannot':341,364 'captur':507 'cast':1252 'categori':692,1336 'check':323,594,723,1291 'ci':1049,1076,1084,1095 'ci/cd':1207 'cicondit':1080,1091 'cionlytest':1089 'clariti':97 'class':80,87,90,124,186,229,235,275,281,297,303,397,420,513,517,553,557,839,886,1114,1119 'classcleanup':277,917,921 'classinit':908 'classiniti':231,904 'cleanup':164,216,259,276,284,913 'client.getasync':385,1274,1281 'code':821 'collect':394,401,404,406,412,414,416,566,569,600,604,608,610 'collectionassert':301,552 'collectionassert.allitemsareinstancesoftype':603 'collectionassert.allitemsarenotnull':607 'collectionassert.allitemsareunique':609 'collectionassert.areequal':576 'collectionassert.areequivalent':587 'collectionassert.arenotequal':579 'collectionassert.arenotequivalent':590 'collectionassert.contains':565 'collectionassert.doesnotcontain':568 'collectionassert.isnotsubsetof':598 'collectionassert.issubsetof':595 'combin':172 'common':1209 'comparison':446 'compil':720 'compile-tim':719 'complet':343,856 'compon':1333 'computedvalu':1021 'condit':330,332,1037 'conditionmode.exclude':1071,1092 'conditionmode.include':1086 'consid':67 'constructor':150,173,195,244,876,1362 'contain':564 'containssingl':1243 'context':910,923,930 'control':686 'convent':56 'cooper':937 'core':304 'correct':1220 'coverag':1194 'coversmultiplerequir':1165 'creat':702 'critic':1354 'cs8618':864,1302 'csharp':2,120,182,306,350,398,421,448,471,501,529,563,616,733,860,941,956,992,1030,1051,1102,1136,1213 'csharp-mstest':1 'current':42,958 'custom':776,1344 'd':438,440,444,543,545,551 'data':19,612,655,705,971,1015 'data-driven':18,611 'datarow':615,618,622,628 'datatestmethod':105 'debug':999 'declar':1312 'default':92,1085 'depend':1373,1380 'deploy':986 'deriv':355 'design':96 'devop':1138 'direct':490 'directori':984 'disabl':1111 'display':690,777,963 'displaynam':626,796,803,809 'dispos':271 'disposeasync':267 'document':851 'donotparallel':1116 'dotnet':77 'driven':20,613 'due':337 'dynamicdata':653,735 'dynamictest':740 'e.g':521,561,1346 'effect':35 'element':409,573,584,601 'enabl':153,193,1356 'environ':1050,1077 'equal':307,318,571 'equival':518,558,582 'error':729 'even':168 'everi':240,261 'ex':358,374,380,388 'ex.message':367 'exact':370,407 'except':345,976,1238,1254 'execut':218,253,1038 'executionscope.methodlevel':1110 'expect':309,423,523,528,532,647,649,746,748,764,790,1219,1222 'expectedbehavior':119,1153 'expectedcollect':577,588 'expectedexcept':349,1225,1227 'expecteditem':400,567 'expectedobject':315 'express':508 'facilit':1377 'fail':171,336,979 'fail/inconclusive':333 'failur':510,1245,1265 'featur':1023,1151,1164,1331 'field':155 'file':991,1006 'filter':1338 'fix':1199 'flaki':1026 'flakytest':1036 'flow':1277 'follow':106,157,662 'generat':1203 'get':4,874,1295,1309,1324 'github':1166 'github.com':1173 'github.com/owner/repo/issues/42':1172 'githubworkitem':1171 'goal':29 'group':1328 'handl':1318 'handler':1256,1267 'hard':1251 'help':32 'high':464 'httpclient.getasync':950 'ienumer':664,674,681,693,712,758,783,816,827 'ignor':1270 'ignoremessag':632,812 'immut':882 'implement':269,273 'includ':13,65 'inform':843 'initasync':205 'initi':209,222,230,238,1316 'inject':877 'int':642,644,646,741,743,745,759,761,763,785,787,789 'interfac':1375 'isol':1366,1382 'isresolv':1179 'issu':634,814,1167 'issue42':1178 'item':987,1002,1122,1130,1140,1147,1156,1181,1240,1248,1250 'itemid':1004 'items.single':1241 'known':633,813 'lead':726,1287 'learn.microsoft.com':853 'learn.microsoft.com/dotnet/core/testing/unit-testing-mstest-writing-tests-testcontext)':852 'least':695 'legacytestdata':829 'level':1104 'lifecycl':148 'link':1126,1144,1197 'linq':1235 'local':1097 'localonlytest':1100 'log':1010 'longrunningtest':948 'low':463 'lowerbound':450,453 'make':1284 'match':352,369 'messag':511,1246 'metadata':689,780,1345 'method':102,242,255,263,360,376,393,706,848,899,914,960,1018,1233 'methodnam':117 'mismatch':732 'mistak':1210 'mix':810 'mock':1364,1372,1378,1379 'modern':14,39,290 'moq':1368 'mstest':3,8,22,25,40,60,293,472,484,499,636,672,754,862,878,915,1028,1039,1124,1168,1299,1317,1358 'mstest.sdk':69 'mstest0020':1360 'multipl':1154 'must':166 'myclass':606 'myhandl':1257 'myservic':190,200 'mytest':887,893 'name':55,113,691,778,961,964,1341 'nameof':736 'need':181,775 'new':135,199,541,549,703,792,799,805,820 'note':514,554,700 'notexpect':312 'notexpectedobject':320 'notsubset':599 'nsubstitut':1370 'nuget':63 'null':322,361,366,870,1290,1298,1311 'nullabl':868,1286,1314 'number':466,468,798 'obj':479,494,497 'object':694,713,715,817,828 'obsolet':1226 'one':408 'operatingsystems.linux':1064 'operatingsystems.macos':1065 'operatingsystems.windows':1058,1072 'option':911 'order':219,575,586,1216 'organ':1327 'os':1047,1053 'os-specif':1052 'oscondit':1057,1063,1070 'output':847,988,996 'packag':64 'parallel':1101,1106 'paramet':477,903 'parameter':969 'pass/fail/inprogress':967 'pattern':112,116,160 'per':225,233,279,287 'perform':94 'phonenumb':442 'pipelin':1208 'plus':685 'posit':797 'practic':6,24,46 'prefer':103,149,347,515,555,668,696,707,753,880,1363 'prefix':426,432,535 'prioriti':1351 'privat':188,888 'process':1001 'project':47,53,72 'projectnam':57 'properti':248,861,955,1305 'provid':294,669,678,682,717,840 'public':122,127,184,196,202,214,638,738,756,781,825,871,884,892,905,918,925,945,1034,1059,1066,1073,1087,1098,1117,1149,1162,1175,1292,1306,1321 'readon':154,189,192,889 'receiv':900 'refer':59,317,857 'regex':542,550 'regress':1201 'relev':1357 'report':1135,1205 'requir':1196 'result':139,146,489,990,1009,1186,1258,1269 'result.count':503 'retri':1024,1032 'return':487,658 'returnssum':131,641 'run':74,167,256,842,954,1043,1081,1096 'runtim':728 'safeti':671,680,684,699,824 'scenario':118,1152 'scope':1109 'screenshot':1011 'screenshotpath':1013 'seal':88,123,185,885,1118 'see':849 'separ':51 'sequentialtest':1120 'servic':191,198 'service.reset':217 'service.warmupasync':212 'servicetest':187,197 'set':246,875,1296,1310,1325 'setup':48,73,179 'sharedkey':1020 'show':1261 'sign':811 'simplifi':71 'singl':1236 'skill' 'skill-csharp-mstest' 'skip':1041,1093 'skiponwindowstest':1075 'sourc':656 'source-github' 'specif':1054,1113 'standard':158 'static':757,782,826,898,906,919,926 'store/retrieve':1014 'string':417 'stringassert':299,512 'stringassert.contains':526,530 'stringassert.doesnotmatch':547 'stringassert.endswith':536 'stringassert.matches':539 'stringassert.startswith':533 'structur':81 'subset':593,596 'suffix':429,435,538 'superset':597 'support':845 'suppress':863,1301 't1':665,676 't2':666,677 'task':204,947 'test':12,21,37,52,58,75,78,79,86,89,101,114,147,170,226,234,237,241,252,254,258,262,280,288,335,340,346,614,688,704,841,953,959,970,978,995,1008,1017,1027,1044,1055,1078,1127,1134,1185,1193,1202,1278,1326,1329,1355,1385 'testcategori':1335 'testclass':83,121,183,883,1115 'testcleanup':162,213,265,982 'testcontext':247,836,838,850,859,872,873,890,891,894,895,896,897,909,922,929,1285,1293,1294,1307,1308,1322,1323 'testcontext.addresultfile':1012 'testcontext.cancellationtoken':935,952,1283 'testcontext.currenttestoutcome':966 'testcontext.deploymentdirectory':983 'testcontext.properties':1019 'testcontext.testdata':968 'testcontext.testdisplayname':962 'testcontext.testexception':975 'testcontext.testname':957 'testcontext.writeline':1000 'testdata':737,765 'testdatarow':710,772,784 'testdatawithmetadata':791 'testiniti':152,176,201,250 'testinitialize/cleanup':974 'testmethod':99,126,617,734,942,1031,1056,1062,1069,1079,1090,1141,1157,1170 'testproperti':1340,1347 'texcept':353 'texton':445 'three':295 'time':721 'timeout':940,943 'token':932,1272 'topic-agent-skills' 'topic-agents' 'topic-awesome' 'topic-custom-agents' 'topic-github-copilot' 'topic-hacktoberfest' 'topic-prompt-engineering' 'trace':1192 'traceabl':1123,1132,1204 'tupl':675 'twopositivenumb':130 'type':356,371,469,482,488,492,663,670,679,683,698,722,731,823,1259,1263 'typed.dosomething':483,495 'typeof':605,1228 'unclear':1237,1253 'unexpectedcollect':580,591 'unexpecteditem':403,570 'unit':11,36,1383 'unixonlytest':1068 'unnecessari':1289 'upperbound':456,459 'url':386,951,1275,1282 'use':41,49,68,82,98,115,161,206,475,867,934,997,1190,1224,1230,1234,1242,1297,1334,1339,1350,1367,1374 'valid':602 'valu':325,327,363,1342 'valuetupl':667,708,752 'var':133,138,357,373,379,387,481,491,1239,1247,1255,1266 'version':378 'void':128,215,639,739,907,920,927,1035,1060,1067,1074,1088,1099,1150,1163,1176 'warn':1320 'windowsonlytest':1061 'without':1313 'work':1121,1129,1139,1146,1155,1180 'worker':1107 'workitem':1142,1158,1160 'write':34,993 'wrong':1214 'x':62,474,486 'x/4.x':10,27 'zero':627,804","prices":[{"id":"3baba2bd-1b11-441b-84ba-5e49e3571e27","listingId":"9b140ee1-7af4-458f-aa98-0a5018a9bdb1","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:07.784Z"}],"sources":[{"listingId":"9b140ee1-7af4-458f-aa98-0a5018a9bdb1","source":"github","sourceId":"github/awesome-copilot/csharp-mstest","sourceUrl":"https://github.com/github/awesome-copilot/tree/main/skills/csharp-mstest","isPrimary":false,"firstSeenAt":"2026-04-18T21:49:00.770Z","lastSeenAt":"2026-05-18T18:52:09.147Z"},{"listingId":"9b140ee1-7af4-458f-aa98-0a5018a9bdb1","source":"skills_sh","sourceId":"github/awesome-copilot/csharp-mstest","sourceUrl":"https://skills.sh/github/awesome-copilot/csharp-mstest","isPrimary":true,"firstSeenAt":"2026-04-18T20:26:07.784Z","lastSeenAt":"2026-05-07T22:40:18.795Z"}],"details":{"listingId":"9b140ee1-7af4-458f-aa98-0a5018a9bdb1","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"github","slug":"csharp-mstest","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":"e68bc31ea88ed3c288a45b593c1f2548101c8a23","skill_md_path":"skills/csharp-mstest/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/github/awesome-copilot/tree/main/skills/csharp-mstest"},"layout":"multi","source":"github","category":"awesome-copilot","frontmatter":{"name":"csharp-mstest","description":"Get best practices for MSTest 3.x/4.x unit testing, including modern assertion APIs and data-driven tests"},"skills_sh_url":"https://skills.sh/github/awesome-copilot/csharp-mstest"},"updatedAt":"2026-05-18T18:52:09.147Z"}}