{"id":"9b140ee1-7af4-458f-aa98-0a5018a9bdb1","shortId":"Vv68n5","kind":"skill","title":"Csharp Mstest","tagline":"Awesome Copilot skill by Github","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"],"capabilities":["skill","source-github","category-awesome-copilot"],"categories":["awesome-copilot"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/github/awesome-copilot/csharp-mstest","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.762Z","embedding":null,"createdAt":"2026-04-18T20:26:07.784Z","updatedAt":"2026-04-22T09:40:13.762Z","lastSeenAt":"2026-04-22T09:40:13.762Z","tsv":"'-1':615,792 '/dotnet/core/testing/unit-testing-mstest-writing-tests-testcontext)':840 '/owner/repo/issues/42':1160 '0':490,609,610,611,617,755,756,757,786,787,788,794,819,820,821,989 '1':206,229,250,605,616,752,779,793,816,1338 '123':621,801 '12345':1129,1134,1145,1335 '2':127,214,231,252,606,753,780,817 '3':12,47,128,222,235,256,425,459,530,607,754,781,818,1019 '3.10':1026 '3.6':865,902 '3.7':659,741,951,958,966 '3.8':623,1111,1155 '3.9':1015 '4':237,427,471,532,1094 '4.0':486 '5':131,243,397 '5000':930 '6':260 '67890':1147 '7':268 'aaa':97 'access':844 'across':1002 'act':95,123 'actual':296,299,437,440,443,446,448,510,513,1204,1209,1248 'actualcollect':564,567,575,578 'actualobject':302,307 'actualstr':410,413,416,419,422,517,520,523,526,534 'add':115,626 'advanc':1008 'alreadi':1286 'alway':919 'analyz':52,1345 'api':29,278 'appear':1169 'approach':702 'argument':1201 'argumentexcept':1215 'arrang':94,118 'arrange-act-assert':93 'assembl':207,213,269,275,1089,1091 'assemblycleanup':271,910,914 'assemblyiniti':209 'assert':96,129,277,282,284,288,291,381,382,404,405,433,456,502,542,1246 'assert.areequal':130,294,348,634,733,1203,1207 'assert.arenotequal':297 'assert.arenotsame':305 'assert.aresame':300 'assert.contains':385,408,508,548 'assert.containssingle':391,1235 'assert.doesnotcontain':388 'assert.doesnotendwith':420 'assert.doesnotmatchregex':429 'assert.doesnotstartwith':417 'assert.endswith':414 'assert.fail':320 'assert.hascount':396 'assert.inconclusive':325 'assert.isempty':399 'assert.isfalse':317 'assert.isgreaterthan':435 'assert.isgreaterthanorequalto':438 'assert.isinrange':447 'assert.isinstanceoftype':464,479,1254 'assert.islessthan':441 'assert.islessthanorequalto':444 'assert.isnegative':453 'assert.isnotempty':401 'assert.isnotinstanceoftype':482 'assert.isnotnull':312 'assert.isnull':310 'assert.ispositive':451 'assert.istrue':315 'assert.matchesregex':423 'assert.startswith':411 'assert.that':484,488 'assert.throws':337,345,1217,1218 'assert.throwsasync':368 'assert.throwsexactly':354,361 'assert.throwsexactlyasync':376 'associ':1168 'async':161,164,189,194,363,369,377,932 'attach':991 'attribut':70 'auto':492 'auto-captur':491 'avail':506,546 'avoid':804,1198 'await':197,367,370,375,378,935,1259,1266 'awesom':3 'azur':1123 'b':631,638,730,737,748,774 'base':1031 'best':9,31 'better':1230 'boolean':314 'bug':1184,1334 'bugfix':1163 'c':145 'calcul':120,122 'calculator.add':126,636,735 'calculatortest':111 'cancel':830,917,924,1257,1265 'cancellationtoken.none':1262 'cannot':327,350 'captur':493 'cast':1238 'categori':678,1322 'category-awesome-copilot' 'check':309,580,709,1277 'ci':1035,1062,1070,1081 'ci/cd':1193 'cicondit':1066,1077 'cionlytest':1075 'clariti':83 'class':66,73,76,110,172,215,221,261,267,283,289,383,406,499,503,539,543,825,872,1100,1105 'classcleanup':263,903,907 'classinit':894 'classiniti':217,890 'cleanup':150,202,245,262,270,899 'client.getasync':371,1260,1267 'code':807 'collect':380,387,390,392,398,400,402,552,555,586,590,594,596 'collectionassert':287,538 'collectionassert.allitemsareinstancesoftype':589 'collectionassert.allitemsarenotnull':593 'collectionassert.allitemsareunique':595 'collectionassert.areequal':562 'collectionassert.areequivalent':573 'collectionassert.arenotequal':565 'collectionassert.arenotequivalent':576 'collectionassert.contains':551 'collectionassert.doesnotcontain':554 'collectionassert.isnotsubsetof':584 'collectionassert.issubsetof':581 'combin':158 'common':1195 'comparison':432 'compil':706 'compile-tim':705 'complet':329,842 'compon':1319 'computedvalu':1007 'condit':316,318,1023 'conditionmode.exclude':1057,1078 'conditionmode.include':1072 'consid':53 'constructor':136,159,181,230,862,1348 'contain':550 'containssingl':1229 'context':896,909,916 'control':672 'convent':42 'cooper':923 'copilot':4 'core':290 'correct':1206 'coverag':1180 'coversmultiplerequir':1151 'creat':688 'critic':1340 'cs8618':850,1288 'csharp':1,106,168,292,336,384,407,434,457,487,515,549,602,719,846,927,942,978,1016,1037,1088,1122,1199 'current':28,944 'custom':762,1330 'd':424,426,430,529,531,537 'data':598,641,691,957,1001 'data-driven':597 'datarow':601,604,608,614 'datatestmethod':91 'debug':985 'declar':1298 'default':78,1071 'depend':1359,1366 'deploy':972 'deriv':341 'design':82 'devop':1124 'direct':476 'directori':970 'disabl':1097 'display':676,763,949 'displaynam':612,782,789,795 'dispos':257 'disposeasync':253 'document':837 'donotparallel':1102 'dotnet':63 'driven':599 'due':323 'dynamicdata':639,721 'dynamictest':726 'e.g':507,547,1332 'effect':21 'element':395,559,570,587 'enabl':139,179,1342 'environ':1036,1063 'equal':293,304,557 'equival':504,544,568 'error':715 'even':154 'everi':226,247 'ex':344,360,366,374 'ex.message':353 'exact':356,393 'except':331,962,1224,1240 'execut':204,239,1024 'executionscope.methodlevel':1096 'expect':295,409,509,514,518,633,635,732,734,750,776,1205,1208 'expectedbehavior':105,1139 'expectedcollect':563,574 'expectedexcept':335,1211,1213 'expecteditem':386,553 'expectedobject':301 'express':494 'facilit':1363 'fail':157,322,965 'fail/inconclusive':319 'failur':496,1231,1251 'featur':1009,1137,1150,1317 'field':141 'file':977,992 'filter':1324 'fix':1185 'flaki':1012 'flakytest':1022 'flow':1263 'follow':92,143,648 'generat':1189 'get':860,1281,1295,1310 'github':7,1152 'github.com':1159 'github.com/owner/repo/issues/42':1158 'githubworkitem':1157 'goal':15 'group':1314 'handl':1304 'handler':1242,1253 'hard':1237 'help':18 'high':450 'httpclient.getasync':936 'ienumer':650,660,667,679,698,744,769,802,813 'ignor':1256 'ignoremessag':618,798 'immut':868 'implement':255,259 'includ':51 'inform':829 'initasync':191 'initi':195,208,216,224,1302 'inject':863 'int':628,630,632,727,729,731,745,747,749,771,773,775 'interfac':1361 'isol':1352,1368 'isresolv':1165 'issu':620,800,1153 'issue42':1164 'item':973,988,1108,1116,1126,1133,1142,1167,1226,1234,1236 'itemid':990 'items.single':1227 'known':619,799 'lead':712,1273 'learn.microsoft.com':839 'learn.microsoft.com/dotnet/core/testing/unit-testing-mstest-writing-tests-testcontext)':838 'least':681 'legacytestdata':815 'level':1090 'lifecycl':134 'link':1112,1130,1183 'linq':1221 'local':1083 'localonlytest':1086 'log':996 'longrunningtest':934 'low':449 'lowerbound':436,439 'make':1270 'match':338,355 'messag':497,1232 'metadata':675,766,1331 'method':88,228,241,249,346,362,379,692,834,885,900,946,1004,1219 'methodnam':103 'mismatch':718 'mistak':1196 'mix':796 'mock':1350,1358,1364,1365 'modern':25,276 'moq':1354 'mstest':2,8,11,26,46,279,458,470,485,622,658,740,848,864,901,1014,1025,1110,1154,1285,1303,1344 'mstest.sdk':55 'mstest0020':1346 'multipl':1140 'must':152 'myclass':592 'myhandl':1243 'myservic':176,186 'mytest':873,879 'name':41,99,677,764,947,950,1327 'nameof':722 'need':167,761 'new':121,185,527,535,689,778,785,791,806 'note':500,540,686 'notexpect':298 'notexpectedobject':306 'notsubset':585 'nsubstitut':1356 'nuget':49 'null':308,347,352,856,1276,1284,1297 'nullabl':854,1272,1300 'number':452,454,784 'obj':465,480,483 'object':680,699,701,803,814 'obsolet':1212 'one':394 'operatingsystems.linux':1050 'operatingsystems.macos':1051 'operatingsystems.windows':1044,1058 'option':897 'order':205,561,572,1202 'organ':1313 'os':1033,1039 'os-specif':1038 'oscondit':1043,1049,1056 'output':833,974,982 'packag':50 'parallel':1087,1092 'paramet':463,889 'parameter':955 'pass/fail/inprogress':953 'pattern':98,102,146 'per':211,219,265,273 'perform':80 'phonenumb':428 'pipelin':1194 'plus':671 'posit':783 'practic':10,32 'prefer':89,135,333,501,541,654,682,693,739,866,1349 'prefix':412,418,521 'prioriti':1337 'privat':174,874 'process':987 'project':33,39,58 'projectnam':43 'properti':234,847,941,1291 'provid':280,655,664,668,703,826 'public':108,113,170,182,188,200,624,724,742,767,811,857,870,878,891,904,911,931,1020,1045,1052,1059,1073,1084,1103,1135,1148,1161,1278,1292,1307 'readon':140,175,178,875 'receiv':886 'refer':45,303,843 'regex':528,536 'regress':1187 'relev':1343 'report':1121,1191 'requir':1182 'result':125,132,475,976,995,1172,1244,1255 'result.count':489 'retri':1010,1018 'return':473,644 'returnssum':117,627 'run':60,153,242,828,940,1029,1067,1082 'runtim':714 'safeti':657,666,670,685,810 'scenario':104,1138 'scope':1095 'screenshot':997 'screenshotpath':999 'seal':74,109,171,871,1104 'see':835 'separ':37 'sequentialtest':1106 'servic':177,184 'service.reset':203 'service.warmupasync':198 'servicetest':173,183 'set':232,861,1282,1296,1311 'setup':34,59,165 'sharedkey':1006 'show':1247 'sign':797 'simplifi':57 'singl':1222 'skill':5 'skip':1027,1079 'skiponwindowstest':1061 'sourc':642 'source-github' 'specif':1040,1099 'standard':144 'static':743,768,812,884,892,905,912 'store/retrieve':1000 'string':403 'stringassert':285,498 'stringassert.contains':512,516 'stringassert.doesnotmatch':533 'stringassert.endswith':522 'stringassert.matches':525 'stringassert.startswith':519 'structur':67 'subset':579,582 'suffix':415,421,524 'superset':583 'support':831 'suppress':849,1287 't1':651,662 't2':652,663 'task':190,933 'test':23,38,44,61,64,65,72,75,87,100,133,156,212,220,223,227,238,240,244,248,266,274,321,326,332,600,674,690,827,939,945,956,964,981,994,1003,1013,1030,1041,1064,1113,1120,1171,1179,1188,1264,1312,1315,1341,1371 'testcategori':1321 'testclass':69,107,169,869,1101 'testcleanup':148,199,251,968 'testcontext':233,822,824,836,845,858,859,876,877,880,881,882,883,895,908,915,1271,1279,1280,1293,1294,1308,1309 'testcontext.addresultfile':998 'testcontext.cancellationtoken':921,938,1269 'testcontext.currenttestoutcome':952 'testcontext.deploymentdirectory':969 'testcontext.properties':1005 'testcontext.testdata':954 'testcontext.testdisplayname':948 'testcontext.testexception':961 'testcontext.testname':943 'testcontext.writeline':986 'testdata':723,751 'testdatarow':696,758,770 'testdatawithmetadata':777 'testiniti':138,162,187,236 'testinitialize/cleanup':960 'testmethod':85,112,603,720,928,1017,1042,1048,1055,1065,1076,1127,1143,1156 'testproperti':1326,1333 'texcept':339 'texton':431 'three':281 'time':707 'timeout':926,929 'token':918,1258 'trace':1178 'traceabl':1109,1118,1190 'tupl':661 'twopositivenumb':116 'type':342,357,455,468,474,478,649,656,665,669,684,708,717,809,1245,1249 'typed.dosomething':469,481 'typeof':591,1214 'unclear':1223,1239 'unexpectedcollect':566,577 'unexpecteditem':389,556 'unit':22,1369 'unixonlytest':1054 'unnecessari':1275 'upperbound':442,445 'url':372,937,1261,1268 'use':27,35,54,68,84,101,147,192,461,853,920,983,1176,1210,1216,1220,1228,1283,1320,1325,1336,1353,1360 'valid':588 'valu':311,313,349,1328 'valuetupl':653,694,738 'var':119,124,343,359,365,373,467,477,1225,1233,1241,1252 'version':364 'void':114,201,625,725,893,906,913,1021,1046,1053,1060,1074,1085,1136,1149,1162 'warn':1306 'windowsonlytest':1047 'without':1299 'work':1107,1115,1125,1132,1141,1166 'worker':1093 'workitem':1128,1144,1146 'write':20,979 'wrong':1200 'x':48,460,472 'x/4.x':13 'zero':613,790","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-04-22T06:52:18.867Z"},{"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-04-22T09:40:13.762Z"}],"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","source":"skills_sh","category":"awesome-copilot","skills_sh_url":"https://skills.sh/github/awesome-copilot/csharp-mstest"},"updatedAt":"2026-04-22T09:40:13.762Z"}}