[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6DYZ4REACKQE57NB6M2NT5C":3,"skill-same:01M6DYZ4REACKQE57NB6M2NT5C":221},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":31,"publishedAt":57,"linkOnly":58,"markdownContent":59,"markdownBody":60,"frontMatter":61,"refName":67,"commitSha":68,"skillDirectory":69,"forksCount":70,"repositoryHtmlUrl":71,"repositoryHomepageUrl":72,"ownerHtmlUrl":73,"ownerBlogUrl":74,"ownerDescription":75,"updatedAt":76,"install":77,"resources":90},"01M6DYZ4REACKQE57NB6M2NT5C","writing-mstest-tests",null,"ALWAYS USE when asked to fix, rewrite, update, improve, modernize, show corrected code for, or explain existing MSTest tests or MSTest-specific configuration. Use for \"review\" when corrected code or edits are wanted, even for one pasted assertion or passing tests with bad failure output. Covers expected\u002Factual labels; generic Boolean, collection, string, numeric, null, identity, exception, hard-cast, and object[] checks; TestContext\u002Flifecycle; timeout\u002Fcancellation; OS\u002FCI conditions, retry, cleanup, parallelization, MSTest.Sdk project setup, and MSTESTxxxx. Honor the installed MSTest version. DO NOT USE to design new test cases (code-testing), perform report-only audits, create project files rather than explain MSTest setup, run tests, migrate frameworks, or handle non-MSTest\u002Fnon-.NET code.","managedcode\u002Fdotnet-skills","managedcode","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F78253589?v=4","01M6DYDJR3EG8KB5G4PC65XCTT","Managed Code","01M6DYDJX0ZT432N04NYJW89DN",514,"MIT","https:\u002F\u002Fgithub.com\u002Fmanagedcode\u002Fdotnet-skills\u002Fblob\u002Fmain\u002Fcatalog\u002FTesting\u002FOfficial-DotNet-Test\u002Fskills\u002Fwriting-mstest-tests\u002FSKILL.md",[18,23,26],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000018","写作与文案",{"categoryNo":27,"categoryName":28,"taxonomyType":29,"taxonomyTypeDesc":30},"01JBSEEDCAT000000000000036","内容创作者","PROFESSION","适用职业",[32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56],"writing","mstest","writing mstest tests","tests","improve","new","when","overlay","labels","retry","project","show","files","only","fix","migrate","testing","collection","ci","code","run","create","cleanup","review","design","2026-11-10 10:12:30",false,"---\nname: writing-mstest-tests\ndescription: >\n  ALWAYS USE when asked to fix, rewrite, update, improve, modernize, show\n  corrected code for, or explain existing MSTest tests or MSTest-specific\n  configuration. Use for \"review\" when corrected code or edits are wanted, even\n  for one pasted assertion or passing tests with bad failure output. Covers\n  expected\u002Factual labels; generic Boolean, collection, string, numeric, null,\n  identity, exception, hard-cast, and object[] checks;\n  TestContext\u002Flifecycle; timeout\u002Fcancellation; OS\u002FCI conditions, retry, cleanup,\n  parallelization, MSTest.Sdk project setup, and MSTESTxxxx. Honor the installed\n  MSTest version. DO NOT USE to design new test cases (code-testing),\n  perform report-only audits, create project files rather than explain MSTest\n  setup, run tests, migrate frameworks, or handle non-MSTest\u002Fnon-.NET code.\nlicense: MIT\nmetadata:\n  portability: portable\n  binding: optional-overlay\n  binding-revision: \"1\"\n---\n\n# Writing MSTest Tests\n\nHelp users write effective MSTest unit tests without exceeding the API level or\nconventions of the project's installed test stack.\n\n## Repository overlay\n\nFor every repository-scoped task where read-only file inspection is allowed,\ncheck `.agents\u002Fskill-overlays\u002Fdotnet-test\u002Fwriting-mstest-tests.md` at the\nrepository root before any other discovery. This includes requests that ask for\ncode or advice without edits; \"do not execute\" does not prohibit reading the\noverlay. If present, read it once before acting and apply its\nrepository-specific naming, layout, framework, and policy bindings.\nRequire its frontmatter to declare `core: dotnet-test\u002Fwriting-mstest-tests`,\n`binding-revision: \"1\"`, and `mode: extend`. If any value is missing or\ndifferent, report the mismatch, ignore the overlay, and continue using this\nskill's portable guidance.\nExplicit user instructions and verified project constraints win over the\noverlay; the overlay wins over portable defaults and examples in this skill. If\nthe file is present but unreadable or conflicts with the repository, report the\nproblem, ignore the overlay, and continue with portable guidance subject to\nverified project constraints. If it is absent, continue normally.\nSkip the lookup only when the task is not tied to a repository or the user\nexplicitly prohibited all file\u002Ftool access. An overlay cannot expand tool\npermissions or the task's scope.\n\n## When to Use\n\n- User wants to improve or modernize existing MSTest tests by implementing concrete fixes\n- User asks about MSTest assertion APIs, data-driven patterns, or test lifecycle\n- User asks to replace `Assert.IsTrue` with more specific assertions (collections, nulls, types, comparisons)\n- User asks to replace hard casts with type-checking assertions in tests\n- User needs help fixing a specific MSTest test bug or failing assertion\n- User asks to fix swapped `Assert.AreEqual` argument order (expected first, actual second)\n- User asks to convert `DynamicData` from `IEnumerable\u003Cobject[]>` to ValueTuple-based data\n- User asks to fix or understand an MSTest analyzer diagnostic (an `MSTESTxxxx` warning\u002Ferror)\n\n## When Not to Use\n\n- User needs a test quality audit, anti-pattern detection, or flaky-test investigation (use `test-anti-patterns`)\n- User needs to run or execute tests (use the `run-tests` skill)\n- User needs to upgrade from MSTest v1\u002Fv2 to v3 (use `migrate-mstest-v1v2-to-v3`)\n- User needs to upgrade from MSTest v3 to v4 (use `migrate-mstest-v3-to-v4`)\n- User needs CI\u002FCD pipeline configuration\n- User is using xUnit, NUnit, or TUnit (not MSTest)\n\n## Inputs\n\n| Input | Required | Description |\n|-------|----------|-------------|\n| Code under test | No | The production code to be tested |\n| Existing test code | No | Current tests to fix, update, or modernize |\n| Test scenario description | No | What behavior the user wants to test |\n\n## Response Guidelines\n\n- **Specific API or pattern questions** (assertions, data-driven, lifecycle): Jump directly to the relevant workflow step. Do not follow the full workflow.\n- **Generate new tests from scratch**: Hand off to `code-testing`; use this\n  skill only as supporting MSTest API\u002Fversion guidance.\n- **Review and fix existing tests**: Fix only the issues present. Do not add unrelated improvements.\n- **Assertion transformations**: Show the corrected call, then state the semantic\n  reason in one sentence. For `Assert.AreEqual`, name `expected` first and\n  `actual` second and explain that this preserves the Expected\u002FActual failure\n  labels.\n- **Bound\u002Fcomparison transformations**: Preserve the condition and put the\n  expected bound(s) first and the observed value last:\n  `score > 0` -> `Assert.IsGreaterThan(0, score)`,\n  `score \u003C 100` -> `Assert.IsLessThan(100, score)`, and\n  `score >= 60 && score \u003C= 90` -> `Assert.IsInRange(60, 90, score)`.\n  Never reverse these arguments to mimic the source expression's left-to-right\n  order.\n- **Exception transformations**: Scope the throwing operation in a lambda,\n  distinguish `ThrowsExactly\u003CT>` (exact type) from `Throws\u003CT>` (type or derived\n  type), and capture the returned exception when properties such as `ParamName`\n  are part of the behavior.\n- **Supplied code requests**: Return complete representative method bodies, not\n  comment-only placeholders. Preserve the real operation and show symmetric\n  setup\u002Fcleanup when lifecycle or environment policy is part of the request.\n\n## Workflow\n\n### Step 1: Determine project setup\n\nCheck the test project, `packages.config`, and assembly reference `HintPath`\nvalues for the exact MSTest version and project system:\n\n- If using `MSTest.Sdk`: resolve its exact version from the project SDK\n  declaration or `global.json` `msbuild-sdks`; do not assume the latest APIs\n- If using `MSTest` metapackage: resolve its exact package version\n- If using `MSTest.TestFramework` + `MSTest.TestAdapter`: check version for feature availability\n- If using classic non-SDK XML (`ToolsVersion`, `Microsoft.CSharp.targets`,\n  explicit `\u003CCompile Include>`) and\u002For `packages.config`: preserve that project\n  system and add each new test file to `\u003CCompile Include>`.\n\nAlso inspect representative tests for custom base fixtures, helper libraries,\nmock syntax, naming, setup, and data builders. Existing conventions and installed\nversions win over the examples below. Do not upgrade MSTest, Moq, NBuilder, or\nthe project format unless the user explicitly asks for a migration.\n\n### MSTest API availability\n\n| API\u002Fpattern | Minimum version | Compatible fallback |\n|---|---:|---|\n| `Assert.ThrowsExactly*`, unified `Assert.Contains` \u002F `HasCount` \u002F `IsEmpty` \u002F `IsNotEmpty` | 3.8 | `Assert.ThrowsException*`, `CollectionAssert`, `StringAssert` |\n| `Assert.IsGreaterThan`, `IsLessThan`, `IsInRange`, `StartsWith`, `EndsWith`, `MatchesRegex` | 3.10 | `Assert.IsTrue` with a clear message, or `StringAssert` |\n| Generic `Assert.IsInstanceOfType\u003CT>(value, out var typed)` | 3.4-3.11 only | Non-generic assertion then post-assert cast on 3.0-3.3; v4 returns the typed value directly |\n| ValueTuple `DynamicData` | 3.7 | `IEnumerable\u003Cobject[]>` |\n| Constructor injection of `TestContext` | 3.6 | Instance `TestContext` property |\n| `[Retry]`, `[OSCondition]` | 3.8 | No built-in retry\u002FOS condition; fix flakiness or retain the existing condition mechanism |\n| `[CICondition]` | 3.10 | Existing project-specific condition mechanism |\n\nFor example, MSTest 3.5.x must not receive `Assert.ThrowsExactly`,\n`Assert.Contains`, ValueTuple `DynamicData`, or constructor-injected\n`TestContext`.\n\nTreat this as a hard gate: after determining the version, do not copy a later\nexample from this skill unless its minimum version is satisfied.\n\nRecommend MSTest.Sdk or the MSTest metapackage only for genuinely new projects:\n\n```xml\n\u003C!-- Option 1: MSTest SDK (simplest, recommended for new projects) -->\n\u003CProject Sdk=\"MSTest.Sdk\">\n  \u003CPropertyGroup>\n    \u003CTargetFramework>net9.0\u003C\u002FTargetFramework>\n  \u003C\u002FPropertyGroup>\n\u003C\u002FProject>\n```\n\nWhen using `MSTest.Sdk`, put the version in `global.json` instead of the project file so all test projects get bumped together:\n\n```json\n{\n  \"msbuild-sdks\": {\n    \"MSTest.Sdk\": \"3.8.2\"\n  }\n}\n```\n\n```xml\n\u003C!-- Option 2: MSTest metapackage -->\n\u003CProject Sdk=\"Microsoft.NET.Sdk\">\n  \u003CPropertyGroup>\n    \u003CTargetFramework>net9.0\u003C\u002FTargetFramework>\n  \u003C\u002FPropertyGroup>\n  \u003CItemGroup>\n    \u003CPackageReference Include=\"MSTest\" Version=\"3.8.2\" \u002F>\n  \u003C\u002FItemGroup>\n\u003C\u002FProject>\n```\n\n### Step 2: Write test classes following conventions\n\nApply these structural conventions only where they do not conflict with the\nsuite's established base classes and lifecycle:\n\n- **Seal test classes** with `sealed` for performance and design clarity\n- Use `[TestClass]` on the class and `[TestMethod]` on test methods\n- Follow the **Arrange-Act-Assert** (AAA) pattern\n- Name tests using `MethodName_Scenario_ExpectedBehavior`\n- Use separate test projects with naming convention `[ProjectName].Tests`\n\n```csharp\n[TestClass]\npublic sealed class OrderServiceTests\n{\n    [TestMethod]\n    public void CalculateTotal_WithDiscount_ReturnsReducedPrice()\n    {\n        \u002F\u002F Arrange\n        var service = new OrderService();\n        var order = new Order { Price = 100m, DiscountPercent = 10 };\n\n        \u002F\u002F Act\n        var total = service.CalculateTotal(order);\n\n        \u002F\u002F Assert\n        Assert.AreEqual(90m, total);\n    }\n}\n```\n\n### Step 3: Use version-compatible assertion APIs\n\nPick the most specific assertion supported by the installed MSTest version.\nMore specific assertions produce better failure messages and make the test's\nintent clear, but uncompilable \"modern\" assertions are worse than compatible\n`StringAssert`, `CollectionAssert`, or `Assert.IsTrue` calls.\n\n| What you are testing | Assertion |\n|---|---|\n| Two values are equal | `Assert.AreEqual(expected, actual)` |\n| Same object instance (reference identity) | `Assert.AreSame(expected, actual)` |\n| Value is null | `Assert.IsNull(value)` |\n| Value is not null | `Assert.IsNotNull(value)` |\n| Collection is empty | `Assert.IsEmpty(collection)` (3.8+) or `CollectionAssert` \u002F count assertion |\n| Collection is not empty | `Assert.IsNotEmpty(collection)` (3.8+) or count assertion |\n| Collection has exactly N items | `Assert.HasCount(N, collection)` (3.8+) or `Assert.AreEqual` on count |\n| Collection contains an item | `Assert.Contains(item, collection)` (3.8+) or `CollectionAssert.Contains` |\n| Collection does not contain an item | `Assert.DoesNotContain(item, collection)` (3.8+) or `CollectionAssert.DoesNotContain` |\n| Object is a specific type | `Assert.IsInstanceOfType\u003CT>(value)` |\n| Code throws an exception | `Assert.ThrowsExactly\u003CT>` (3.8+) or `Assert.ThrowsException\u003CT>` (earlier) |\n\nOn MSTest 3.8+, prefer `Assert` class methods over `StringAssert` or\n`CollectionAssert` where both exist. Older versions should keep the compatible\nspecialized classes.\nWhen several independent collection properties were requested, keep each\nsemantic check explicit even if another assertion happens to imply it. For\nexample, retain `IsNotEmpty` when the requested diagnostics distinguish\nempty\u002Fnon-empty, then use `HasCount` and `ContainsSingle` for their separate\ncardinality guarantees.\n\n#### Equality, null, and reference checks\n\n```csharp\nAssert.AreEqual(expected, actual);      \u002F\u002F Value equality\nAssert.AreSame(expected, actual);       \u002F\u002F Reference equality -- same object instance\nAssert.IsNull(value);\nAssert.IsNotNull(value);\n```\n\n#### Exception testing\n\n```csharp\n\u002F\u002F MSTest 3.8+\nvar ex = Assert.ThrowsExactly\u003CArgumentNullException>(() => service.Process(null));\nAssert.AreEqual(\"input\", ex.ParamName);\n\n\u002F\u002F Async\nvar ex = await Assert.ThrowsExactlyAsync\u003CInvalidOperationException>(\n    async () => await service.ProcessAsync(null));\n```\n\n- `Assert.Throws\u003CT>` matches `T` or any derived type\n- `Assert.ThrowsExactly\u003CT>` matches only the exact type `T`\n\nOn MSTest 3.7 and earlier, use the compatible API:\n\n```csharp\nvar ex = Assert.ThrowsException\u003CArgumentNullException>(\n    () => service.Process(null));\n```\n\n#### Collection assertions\n\n```csharp\n\u002F\u002F MSTest 3.8+\nAssert.Contains(expectedItem, collection);\nAssert.DoesNotContain(unexpectedItem, collection);\nvar single = Assert.ContainsSingle(collection);  \u002F\u002F Returns the single element\nAssert.HasCount(3, collection);\nAssert.IsEmpty(collection);\nAssert.IsNotEmpty(collection);\n```\n\nOn earlier versions use `CollectionAssert.Contains`,\n`CollectionAssert.DoesNotContain`, and `Assert.AreEqual(expectedCount,\ncollection.Count)`.\n\nReplace generic `Assert.IsTrue` with specialized assertions -- they give better failure messages:\n\n| Instead of | Use |\n|---|---|\n| `Assert.IsTrue(list.Count > 0)` | `Assert.IsNotEmpty(list)` |\n| `Assert.IsTrue(list.Count == 0)` | `Assert.IsEmpty(list)` |\n| `Assert.IsTrue(list.Count() == 3)` | `Assert.HasCount(3, list)` |\n| `Assert.IsTrue(x != null)` | `Assert.IsNotNull(x)` |\n| `Assert.IsTrue(x == null)` | `Assert.IsNull(x)` |\n| `Assert.AreEqual(a, b)` for same instance | `Assert.AreSame(a, b)` -- reference identity |\n| `Assert.IsTrue(!list.Contains(item))` | `Assert.DoesNotContain(item, list)` |\n| `list.Single(predicate)` + `Assert.IsNotNull` | `Assert.ContainsSingle(list)` |\n| `Assert.IsTrue(list.Contains(item))` | `Assert.Contains(item, list)` |\n\n#### String assertions\n\n```csharp\n\u002F\u002F MSTest 3.10+\nAssert.Contains(\"expected\", actualString);\nAssert.StartsWith(\"prefix\", actualString);\nAssert.EndsWith(\"suffix\", actualString);\nAssert.MatchesRegex(@\"\\d{3}-\\d{4}\", phoneNumber);\n```\n\nOn earlier versions use `StringAssert.Contains`, `StringAssert.StartsWith`,\n`StringAssert.EndsWith`, and `StringAssert.Matches`.\n\n#### Type assertions\n\nMSTest 3.x is not one API level. Pick the form supported by the installed\nminor version:\n\n```csharp\n\u002F\u002F MSTest 3.0-3.3\nAssert.IsInstanceOfType(result, typeof(MyHandler));\nvar typed = (MyHandler)result; \u002F\u002F Safe because the assertion stops a mismatch.\n```\n\n```csharp\n\u002F\u002F MSTest 3.4-3.11 -- out parameter\nAssert.IsInstanceOfType\u003CMyHandler>(result, out var typed);\ntyped.Handle();\n```\n\n```csharp\n\u002F\u002F MSTest 4.x -- returns the proven value directly\nvar typed = Assert.IsInstanceOfType\u003CMyHandler>(result);\n```\n\n#### Comparison assertions\n\n```csharp\nAssert.IsGreaterThan(lowerBound, actual);\nAssert.IsLessThan(upperBound, actual);\nAssert.IsInRange(low, high, actual);\n```\n\n### Step 4: Use data-driven tests for multiple inputs\n\n#### DataRow for inline values\n\n```csharp\n[TestMethod]\n[DataRow(1, 2, 3)]\n[DataRow(0, 0, 0, DisplayName = \"Zeros\")]\n[DataRow(-1, 1, 0)]\npublic void Add_ReturnsExpectedSum(int a, int b, int expected)\n{\n    Assert.AreEqual(expected, Calculator.Add(a, b));\n}\n```\n\n#### DynamicData with ValueTuples (preferred for complex data)\n\nOn MSTest 3.7+, prefer `ValueTuple` return types over\n`IEnumerable\u003Cobject[]>` for type safety. Keep `IEnumerable\u003Cobject[]>` on older\nversions.\n\nTuple element names document which position maps to which test parameter, and\ntuple element types catch incompatible values at compile time. They do **not**\nmake `DynamicData` position-independent, and swapping two same-typed elements\ncan still compile. Do not claim otherwise. When rows need custom display names\nor metadata rather than only typed positional data, use `TestDataRow\u003CT>` on\nMSTest 3.8+.\n\n```csharp\n[TestMethod]\n[DynamicData(nameof(DiscountTestData))]\npublic void ApplyDiscount_ReturnsExpectedPrice(decimal price, int percent, decimal expected)\n{\n    var result = PriceCalculator.ApplyDiscount(price, percent);\n    Assert.AreEqual(expected, result);\n}\n\n\u002F\u002F ValueTuple -- preferred (MSTest 3.7+)\npublic static IEnumerable\u003C(decimal price, int percent, decimal expected)> DiscountTestData =>\n[\n    (100m, 10, 90m),\n    (200m, 25, 150m),\n    (50m, 0, 50m),\n];\n```\n\nWhen you need metadata per test case on MSTest 3.8+, use `TestDataRow\u003CT>`:\n\n```csharp\npublic static IEnumerable\u003CTestDataRow\u003C(decimal price, int percent, decimal expected)>> DiscountTestDataWithMetadata =>\n[\n    new((100m, 10, 90m)) { DisplayName = \"10% discount\" },\n    new((200m, 25, 150m)) { DisplayName = \"25% discount\" },\n    new((50m, 0, 50m)) { DisplayName = \"No discount\" },\n];\n```\n\n### Step 5: Handle test lifecycle correctly\n\n- Prefer constructor initialization when the existing suite supports it; retain a shared `FixtureBase\u003CTSut>` or established `[TestInitialize]` lifecycle rather than rewriting the fixture architecture incidentally.\n- Use `[TestInitialize]` **only** for async initialization, combined with the constructor for sync parts\n- Use `[TestCleanup]` for cleanup that must run even on failure\n- Inject `TestContext` via constructor only on MSTest 3.6+; otherwise use the instance property.\n\n```csharp\n[TestClass]\npublic sealed class RepositoryTests\n{\n    private readonly TestContext _testContext;\n    private readonly FakeDatabase _db;  \u002F\u002F readonly -- guaranteed by constructor\n\n    public RepositoryTests(TestContext testContext)\n    {\n        _testContext = testContext;\n        _db = new FakeDatabase();  \u002F\u002F sync init in ctor\n    }\n\n    [TestInitialize]\n    public async Task InitAsync()\n    {\n        \u002F\u002F Use TestInitialize ONLY for async setup\n        await _db.SeedAsync();\n    }\n\n    [TestCleanup]\n    public void Cleanup() => _db.Reset();\n}\n```\n\n#### Execution order\n\n1. `[AssemblyInitialize]` -- once per assembly\n2. `[ClassInitialize]` -- once per class\n3. Per test:\n   - With `TestContext` property injection: Constructor -> set `TestContext` property -> `[TestInitialize]`\n   - With constructor injection of `TestContext`: Constructor (receives `TestContext`) -> `[TestInitialize]`\n4. Test method\n5. `[TestCleanup]` -> `DisposeAsync` -> `Dispose` -- per test\n6. `[ClassCleanup]` -- once per class\n7. `[AssemblyCleanup]` -- once per assembly\n\n### Step 6: Apply cancellation and timeout patterns\n\nUse `TestContext.CancellationToken` with\n`[Timeout(milliseconds, CooperativeCancellation = true)]` when the installed\nMSTest version exposes the token directly (3.11+). On MSTest 3.6.4-3.10, use\n`TestContext.CancellationTokenSource.Token` with cooperative cancellation\ninstead. A plain `[Timeout]` does not establish that the framework token will\nstop in-flight work. On older versions, use a test-owned\n`CancellationTokenSource` where cancellation itself is under test.\n\n```csharp\n\u002F\u002F MSTest 3.11+\n[TestMethod]\n[Timeout(5000, CooperativeCancellation = true)]\npublic async Task FetchData_ReturnsWithinTimeout()\n{\n    var result = await _client.GetDataAsync(_testContext.CancellationToken);\n    Assert.IsNotNull(result);\n}\n```\n\n### Step 7: Use advanced features where appropriate\n\nFor retry, conditional execution, or parallelization requests, read\n[Advanced MSTest patterns](references\u002Fadvanced-mstest-patterns.md). Apply its\nversion gates and keep the real tested operation, assertion, and cleanup.\n\n### Step 8: Fix MSTest analyzer diagnostics (MSTESTxxxx)\n\nFor an `MSTESTxxxx` request, read\n[Advanced MSTest patterns](references\u002Fadvanced-mstest-patterns.md), apply the\nversion-compatible fix for that rule, and rebuild to confirm the diagnostic is\ngone. Prefer fixing the code over suppressing the rule.\n\n### Step 9: Verify file-backed corrections\n\nWhen the user asked for repository edits and did not prohibit execution, run the\nnarrowest affected `dotnet test` command after editing. A successful process with\nno discovered-test count is not verification. Require the intended test cases to\nbe discovered and pass.\n\nIf compilation exposes a directly coupled source issue that prevents the\ncorrected existing suite from running (for example, a missing namespace import\nin the supplied production file), make only that minimum fix and rerun. Do not\nupgrade packages or broaden the modernization. Report the actual test count and\nthe fixes made; never present unrun or output-free tests as passing.\nIn the final handoff, map every requested modernization to the exact corrected\nconstruct and cite the passing test command. Do not rely on a generic \"modernized\"\nsummary when expected\u002Factual order, exact type checks, data discovery, or class\nshape were explicit requirements.\n","# Writing MSTest Tests\n\nHelp users write effective MSTest unit tests without exceeding the API level or\nconventions of the project's installed test stack.\n\n## Repository overlay\n\nFor every repository-scoped task where read-only file inspection is allowed,\ncheck `.agents\u002Fskill-overlays\u002Fdotnet-test\u002Fwriting-mstest-tests.md` at the\nrepository root before any other discovery. This includes requests that ask for\ncode or advice without edits; \"do not execute\" does not prohibit reading the\noverlay. If present, read it once before acting and apply its\nrepository-specific naming, layout, framework, and policy bindings.\nRequire its frontmatter to declare `core: dotnet-test\u002Fwriting-mstest-tests`,\n`binding-revision: \"1\"`, and `mode: extend`. If any value is missing or\ndifferent, report the mismatch, ignore the overlay, and continue using this\nskill's portable guidance.\nExplicit user instructions and verified project constraints win over the\noverlay; the overlay wins over portable defaults and examples in this skill. If\nthe file is present but unreadable or conflicts with the repository, report the\nproblem, ignore the overlay, and continue with portable guidance subject to\nverified project constraints. If it is absent, continue normally.\nSkip the lookup only when the task is not tied to a repository or the user\nexplicitly prohibited all file\u002Ftool access. An overlay cannot expand tool\npermissions or the task's scope.\n\n## When to Use\n\n- User wants to improve or modernize existing MSTest tests by implementing concrete fixes\n- User asks about MSTest assertion APIs, data-driven patterns, or test lifecycle\n- User asks to replace `Assert.IsTrue` with more specific assertions (collections, nulls, types, comparisons)\n- User asks to replace hard casts with type-checking assertions in tests\n- User needs help fixing a specific MSTest test bug or failing assertion\n- User asks to fix swapped `Assert.AreEqual` argument order (expected first, actual second)\n- User asks to convert `DynamicData` from `IEnumerable\u003Cobject[]>` to ValueTuple-based data\n- User asks to fix or understand an MSTest analyzer diagnostic (an `MSTESTxxxx` warning\u002Ferror)\n\n## When Not to Use\n\n- User needs a test quality audit, anti-pattern detection, or flaky-test investigation (use `test-anti-patterns`)\n- User needs to run or execute tests (use the `run-tests` skill)\n- User needs to upgrade from MSTest v1\u002Fv2 to v3 (use `migrate-mstest-v1v2-to-v3`)\n- User needs to upgrade from MSTest v3 to v4 (use `migrate-mstest-v3-to-v4`)\n- User needs CI\u002FCD pipeline configuration\n- User is using xUnit, NUnit, or TUnit (not MSTest)\n\n## Inputs\n\n| Input | Required | Description |\n|-------|----------|-------------|\n| Code under test | No | The production code to be tested |\n| Existing test code | No | Current tests to fix, update, or modernize |\n| Test scenario description | No | What behavior the user wants to test |\n\n## Response Guidelines\n\n- **Specific API or pattern questions** (assertions, data-driven, lifecycle): Jump directly to the relevant workflow step. Do not follow the full workflow.\n- **Generate new tests from scratch**: Hand off to `code-testing`; use this\n  skill only as supporting MSTest API\u002Fversion guidance.\n- **Review and fix existing tests**: Fix only the issues present. Do not add unrelated improvements.\n- **Assertion transformations**: Show the corrected call, then state the semantic\n  reason in one sentence. For `Assert.AreEqual`, name `expected` first and\n  `actual` second and explain that this preserves the Expected\u002FActual failure\n  labels.\n- **Bound\u002Fcomparison transformations**: Preserve the condition and put the\n  expected bound(s) first and the observed value last:\n  `score > 0` -> `Assert.IsGreaterThan(0, score)`,\n  `score \u003C 100` -> `Assert.IsLessThan(100, score)`, and\n  `score >= 60 && score \u003C= 90` -> `Assert.IsInRange(60, 90, score)`.\n  Never reverse these arguments to mimic the source expression's left-to-right\n  order.\n- **Exception transformations**: Scope the throwing operation in a lambda,\n  distinguish `ThrowsExactly\u003CT>` (exact type) from `Throws\u003CT>` (type or derived\n  type), and capture the returned exception when properties such as `ParamName`\n  are part of the behavior.\n- **Supplied code requests**: Return complete representative method bodies, not\n  comment-only placeholders. Preserve the real operation and show symmetric\n  setup\u002Fcleanup when lifecycle or environment policy is part of the request.\n\n## Workflow\n\n### Step 1: Determine project setup\n\nCheck the test project, `packages.config`, and assembly reference `HintPath`\nvalues for the exact MSTest version and project system:\n\n- If using `MSTest.Sdk`: resolve its exact version from the project SDK\n  declaration or `global.json` `msbuild-sdks`; do not assume the latest APIs\n- If using `MSTest` metapackage: resolve its exact package version\n- If using `MSTest.TestFramework` + `MSTest.TestAdapter`: check version for feature availability\n- If using classic non-SDK XML (`ToolsVersion`, `Microsoft.CSharp.targets`,\n  explicit `\u003CCompile Include>`) and\u002For `packages.config`: preserve that project\n  system and add each new test file to `\u003CCompile Include>`.\n\nAlso inspect representative tests for custom base fixtures, helper libraries,\nmock syntax, naming, setup, and data builders. Existing conventions and installed\nversions win over the examples below. Do not upgrade MSTest, Moq, NBuilder, or\nthe project format unless the user explicitly asks for a migration.\n\n### MSTest API availability\n\n| API\u002Fpattern | Minimum version | Compatible fallback |\n|---|---:|---|\n| `Assert.ThrowsExactly*`, unified `Assert.Contains` \u002F `HasCount` \u002F `IsEmpty` \u002F `IsNotEmpty` | 3.8 | `Assert.ThrowsException*`, `CollectionAssert`, `StringAssert` |\n| `Assert.IsGreaterThan`, `IsLessThan`, `IsInRange`, `StartsWith`, `EndsWith`, `MatchesRegex` | 3.10 | `Assert.IsTrue` with a clear message, or `StringAssert` |\n| Generic `Assert.IsInstanceOfType\u003CT>(value, out var typed)` | 3.4-3.11 only | Non-generic assertion then post-assert cast on 3.0-3.3; v4 returns the typed value directly |\n| ValueTuple `DynamicData` | 3.7 | `IEnumerable\u003Cobject[]>` |\n| Constructor injection of `TestContext` | 3.6 | Instance `TestContext` property |\n| `[Retry]`, `[OSCondition]` | 3.8 | No built-in retry\u002FOS condition; fix flakiness or retain the existing condition mechanism |\n| `[CICondition]` | 3.10 | Existing project-specific condition mechanism |\n\nFor example, MSTest 3.5.x must not receive `Assert.ThrowsExactly`,\n`Assert.Contains`, ValueTuple `DynamicData`, or constructor-injected\n`TestContext`.\n\nTreat this as a hard gate: after determining the version, do not copy a later\nexample from this skill unless its minimum version is satisfied.\n\nRecommend MSTest.Sdk or the MSTest metapackage only for genuinely new projects:\n\n```xml\n\u003C!-- Option 1: MSTest SDK (simplest, recommended for new projects) -->\n\u003CProject Sdk=\"MSTest.Sdk\">\n  \u003CPropertyGroup>\n    \u003CTargetFramework>net9.0\u003C\u002FTargetFramework>\n  \u003C\u002FPropertyGroup>\n\u003C\u002FProject>\n```\n\nWhen using `MSTest.Sdk`, put the version in `global.json` instead of the project file so all test projects get bumped together:\n\n```json\n{\n  \"msbuild-sdks\": {\n    \"MSTest.Sdk\": \"3.8.2\"\n  }\n}\n```\n\n```xml\n\u003C!-- Option 2: MSTest metapackage -->\n\u003CProject Sdk=\"Microsoft.NET.Sdk\">\n  \u003CPropertyGroup>\n    \u003CTargetFramework>net9.0\u003C\u002FTargetFramework>\n  \u003C\u002FPropertyGroup>\n  \u003CItemGroup>\n    \u003CPackageReference Include=\"MSTest\" Version=\"3.8.2\" \u002F>\n  \u003C\u002FItemGroup>\n\u003C\u002FProject>\n```\n\n### Step 2: Write test classes following conventions\n\nApply these structural conventions only where they do not conflict with the\nsuite's established base classes and lifecycle:\n\n- **Seal test classes** with `sealed` for performance and design clarity\n- Use `[TestClass]` on the class and `[TestMethod]` on test methods\n- Follow the **Arrange-Act-Assert** (AAA) pattern\n- Name tests using `MethodName_Scenario_ExpectedBehavior`\n- Use separate test projects with naming convention `[ProjectName].Tests`\n\n```csharp\n[TestClass]\npublic sealed class OrderServiceTests\n{\n    [TestMethod]\n    public void CalculateTotal_WithDiscount_ReturnsReducedPrice()\n    {\n        \u002F\u002F Arrange\n        var service = new OrderService();\n        var order = new Order { Price = 100m, DiscountPercent = 10 };\n\n        \u002F\u002F Act\n        var total = service.CalculateTotal(order);\n\n        \u002F\u002F Assert\n        Assert.AreEqual(90m, total);\n    }\n}\n```\n\n### Step 3: Use version-compatible assertion APIs\n\nPick the most specific assertion supported by the installed MSTest version.\nMore specific assertions produce better failure messages and make the test's\nintent clear, but uncompilable \"modern\" assertions are worse than compatible\n`StringAssert`, `CollectionAssert`, or `Assert.IsTrue` calls.\n\n| What you are testing | Assertion |\n|---|---|\n| Two values are equal | `Assert.AreEqual(expected, actual)` |\n| Same object instance (reference identity) | `Assert.AreSame(expected, actual)` |\n| Value is null | `Assert.IsNull(value)` |\n| Value is not null | `Assert.IsNotNull(value)` |\n| Collection is empty | `Assert.IsEmpty(collection)` (3.8+) or `CollectionAssert` \u002F count assertion |\n| Collection is not empty | `Assert.IsNotEmpty(collection)` (3.8+) or count assertion |\n| Collection has exactly N items | `Assert.HasCount(N, collection)` (3.8+) or `Assert.AreEqual` on count |\n| Collection contains an item | `Assert.Contains(item, collection)` (3.8+) or `CollectionAssert.Contains` |\n| Collection does not contain an item | `Assert.DoesNotContain(item, collection)` (3.8+) or `CollectionAssert.DoesNotContain` |\n| Object is a specific type | `Assert.IsInstanceOfType\u003CT>(value)` |\n| Code throws an exception | `Assert.ThrowsExactly\u003CT>` (3.8+) or `Assert.ThrowsException\u003CT>` (earlier) |\n\nOn MSTest 3.8+, prefer `Assert` class methods over `StringAssert` or\n`CollectionAssert` where both exist. Older versions should keep the compatible\nspecialized classes.\nWhen several independent collection properties were requested, keep each\nsemantic check explicit even if another assertion happens to imply it. For\nexample, retain `IsNotEmpty` when the requested diagnostics distinguish\nempty\u002Fnon-empty, then use `HasCount` and `ContainsSingle` for their separate\ncardinality guarantees.\n\n#### Equality, null, and reference checks\n\n```csharp\nAssert.AreEqual(expected, actual);      \u002F\u002F Value equality\nAssert.AreSame(expected, actual);       \u002F\u002F Reference equality -- same object instance\nAssert.IsNull(value);\nAssert.IsNotNull(value);\n```\n\n#### Exception testing\n\n```csharp\n\u002F\u002F MSTest 3.8+\nvar ex = Assert.ThrowsExactly\u003CArgumentNullException>(() => service.Process(null));\nAssert.AreEqual(\"input\", ex.ParamName);\n\n\u002F\u002F Async\nvar ex = await Assert.ThrowsExactlyAsync\u003CInvalidOperationException>(\n    async () => await service.ProcessAsync(null));\n```\n\n- `Assert.Throws\u003CT>` matches `T` or any derived type\n- `Assert.ThrowsExactly\u003CT>` matches only the exact type `T`\n\nOn MSTest 3.7 and earlier, use the compatible API:\n\n```csharp\nvar ex = Assert.ThrowsException\u003CArgumentNullException>(\n    () => service.Process(null));\n```\n\n#### Collection assertions\n\n```csharp\n\u002F\u002F MSTest 3.8+\nAssert.Contains(expectedItem, collection);\nAssert.DoesNotContain(unexpectedItem, collection);\nvar single = Assert.ContainsSingle(collection);  \u002F\u002F Returns the single element\nAssert.HasCount(3, collection);\nAssert.IsEmpty(collection);\nAssert.IsNotEmpty(collection);\n```\n\nOn earlier versions use `CollectionAssert.Contains`,\n`CollectionAssert.DoesNotContain`, and `Assert.AreEqual(expectedCount,\ncollection.Count)`.\n\nReplace generic `Assert.IsTrue` with specialized assertions -- they give better failure messages:\n\n| Instead of | Use |\n|---|---|\n| `Assert.IsTrue(list.Count > 0)` | `Assert.IsNotEmpty(list)` |\n| `Assert.IsTrue(list.Count == 0)` | `Assert.IsEmpty(list)` |\n| `Assert.IsTrue(list.Count() == 3)` | `Assert.HasCount(3, list)` |\n| `Assert.IsTrue(x != null)` | `Assert.IsNotNull(x)` |\n| `Assert.IsTrue(x == null)` | `Assert.IsNull(x)` |\n| `Assert.AreEqual(a, b)` for same instance | `Assert.AreSame(a, b)` -- reference identity |\n| `Assert.IsTrue(!list.Contains(item))` | `Assert.DoesNotContain(item, list)` |\n| `list.Single(predicate)` + `Assert.IsNotNull` | `Assert.ContainsSingle(list)` |\n| `Assert.IsTrue(list.Contains(item))` | `Assert.Contains(item, list)` |\n\n#### String assertions\n\n```csharp\n\u002F\u002F MSTest 3.10+\nAssert.Contains(\"expected\", actualString);\nAssert.StartsWith(\"prefix\", actualString);\nAssert.EndsWith(\"suffix\", actualString);\nAssert.MatchesRegex(@\"\\d{3}-\\d{4}\", phoneNumber);\n```\n\nOn earlier versions use `StringAssert.Contains`, `StringAssert.StartsWith`,\n`StringAssert.EndsWith`, and `StringAssert.Matches`.\n\n#### Type assertions\n\nMSTest 3.x is not one API level. Pick the form supported by the installed\nminor version:\n\n```csharp\n\u002F\u002F MSTest 3.0-3.3\nAssert.IsInstanceOfType(result, typeof(MyHandler));\nvar typed = (MyHandler)result; \u002F\u002F Safe because the assertion stops a mismatch.\n```\n\n```csharp\n\u002F\u002F MSTest 3.4-3.11 -- out parameter\nAssert.IsInstanceOfType\u003CMyHandler>(result, out var typed);\ntyped.Handle();\n```\n\n```csharp\n\u002F\u002F MSTest 4.x -- returns the proven value directly\nvar typed = Assert.IsInstanceOfType\u003CMyHandler>(result);\n```\n\n#### Comparison assertions\n\n```csharp\nAssert.IsGreaterThan(lowerBound, actual);\nAssert.IsLessThan(upperBound, actual);\nAssert.IsInRange(low, high, actual);\n```\n\n### Step 4: Use data-driven tests for multiple inputs\n\n#### DataRow for inline values\n\n```csharp\n[TestMethod]\n[DataRow(1, 2, 3)]\n[DataRow(0, 0, 0, DisplayName = \"Zeros\")]\n[DataRow(-1, 1, 0)]\npublic void Add_ReturnsExpectedSum(int a, int b, int expected)\n{\n    Assert.AreEqual(expected, Calculator.Add(a, b));\n}\n```\n\n#### DynamicData with ValueTuples (preferred for complex data)\n\nOn MSTest 3.7+, prefer `ValueTuple` return types over\n`IEnumerable\u003Cobject[]>` for type safety. Keep `IEnumerable\u003Cobject[]>` on older\nversions.\n\nTuple element names document which position maps to which test parameter, and\ntuple element types catch incompatible values at compile time. They do **not**\nmake `DynamicData` position-independent, and swapping two same-typed elements\ncan still compile. Do not claim otherwise. When rows need custom display names\nor metadata rather than only typed positional data, use `TestDataRow\u003CT>` on\nMSTest 3.8+.\n\n```csharp\n[TestMethod]\n[DynamicData(nameof(DiscountTestData))]\npublic void ApplyDiscount_ReturnsExpectedPrice(decimal price, int percent, decimal expected)\n{\n    var result = PriceCalculator.ApplyDiscount(price, percent);\n    Assert.AreEqual(expected, result);\n}\n\n\u002F\u002F ValueTuple -- preferred (MSTest 3.7+)\npublic static IEnumerable\u003C(decimal price, int percent, decimal expected)> DiscountTestData =>\n[\n    (100m, 10, 90m),\n    (200m, 25, 150m),\n    (50m, 0, 50m),\n];\n```\n\nWhen you need metadata per test case on MSTest 3.8+, use `TestDataRow\u003CT>`:\n\n```csharp\npublic static IEnumerable\u003CTestDataRow\u003C(decimal price, int percent, decimal expected)>> DiscountTestDataWithMetadata =>\n[\n    new((100m, 10, 90m)) { DisplayName = \"10% discount\" },\n    new((200m, 25, 150m)) { DisplayName = \"25% discount\" },\n    new((50m, 0, 50m)) { DisplayName = \"No discount\" },\n];\n```\n\n### Step 5: Handle test lifecycle correctly\n\n- Prefer constructor initialization when the existing suite supports it; retain a shared `FixtureBase\u003CTSut>` or established `[TestInitialize]` lifecycle rather than rewriting the fixture architecture incidentally.\n- Use `[TestInitialize]` **only** for async initialization, combined with the constructor for sync parts\n- Use `[TestCleanup]` for cleanup that must run even on failure\n- Inject `TestContext` via constructor only on MSTest 3.6+; otherwise use the instance property.\n\n```csharp\n[TestClass]\npublic sealed class RepositoryTests\n{\n    private readonly TestContext _testContext;\n    private readonly FakeDatabase _db;  \u002F\u002F readonly -- guaranteed by constructor\n\n    public RepositoryTests(TestContext testContext)\n    {\n        _testContext = testContext;\n        _db = new FakeDatabase();  \u002F\u002F sync init in ctor\n    }\n\n    [TestInitialize]\n    public async Task InitAsync()\n    {\n        \u002F\u002F Use TestInitialize ONLY for async setup\n        await _db.SeedAsync();\n    }\n\n    [TestCleanup]\n    public void Cleanup() => _db.Reset();\n}\n```\n\n#### Execution order\n\n1. `[AssemblyInitialize]` -- once per assembly\n2. `[ClassInitialize]` -- once per class\n3. Per test:\n   - With `TestContext` property injection: Constructor -> set `TestContext` property -> `[TestInitialize]`\n   - With constructor injection of `TestContext`: Constructor (receives `TestContext`) -> `[TestInitialize]`\n4. Test method\n5. `[TestCleanup]` -> `DisposeAsync` -> `Dispose` -- per test\n6. `[ClassCleanup]` -- once per class\n7. `[AssemblyCleanup]` -- once per assembly\n\n### Step 6: Apply cancellation and timeout patterns\n\nUse `TestContext.CancellationToken` with\n`[Timeout(milliseconds, CooperativeCancellation = true)]` when the installed\nMSTest version exposes the token directly (3.11+). On MSTest 3.6.4-3.10, use\n`TestContext.CancellationTokenSource.Token` with cooperative cancellation\ninstead. A plain `[Timeout]` does not establish that the framework token will\nstop in-flight work. On older versions, use a test-owned\n`CancellationTokenSource` where cancellation itself is under test.\n\n```csharp\n\u002F\u002F MSTest 3.11+\n[TestMethod]\n[Timeout(5000, CooperativeCancellation = true)]\npublic async Task FetchData_ReturnsWithinTimeout()\n{\n    var result = await _client.GetDataAsync(_testContext.CancellationToken);\n    Assert.IsNotNull(result);\n}\n```\n\n### Step 7: Use advanced features where appropriate\n\nFor retry, conditional execution, or parallelization requests, read\n[Advanced MSTest patterns](references\u002Fadvanced-mstest-patterns.md). Apply its\nversion gates and keep the real tested operation, assertion, and cleanup.\n\n### Step 8: Fix MSTest analyzer diagnostics (MSTESTxxxx)\n\nFor an `MSTESTxxxx` request, read\n[Advanced MSTest patterns](references\u002Fadvanced-mstest-patterns.md), apply the\nversion-compatible fix for that rule, and rebuild to confirm the diagnostic is\ngone. Prefer fixing the code over suppressing the rule.\n\n### Step 9: Verify file-backed corrections\n\nWhen the user asked for repository edits and did not prohibit execution, run the\nnarrowest affected `dotnet test` command after editing. A successful process with\nno discovered-test count is not verification. Require the intended test cases to\nbe discovered and pass.\n\nIf compilation exposes a directly coupled source issue that prevents the\ncorrected existing suite from running (for example, a missing namespace import\nin the supplied production file), make only that minimum fix and rerun. Do not\nupgrade packages or broaden the modernization. Report the actual test count and\nthe fixes made; never present unrun or output-free tests as passing.\nIn the final handoff, map every requested modernization to the exact corrected\nconstruct and cite the passing test command. Do not rely on a generic \"modernized\"\nsummary when expected\u002Factual order, exact type checks, data discovery, or class\nshape were explicit requirements.\n",{"name":5,"license":15,"metadata":62,"description":66},{"binding":63,"portability":64,"binding-revision":65},"optional-overlay","portable","1","ALWAYS USE when asked to fix, rewrite, update, improve, modernize, show corrected code for, or explain existing MSTest tests or MSTest-specific configuration. Use for \"review\" when corrected code or edits are wanted, even for one pasted assertion or passing tests with bad failure output. Covers expected\u002Factual labels; generic Boolean, collection, string, numeric, null, identity, exception, hard-cast, and object[] checks; TestContext\u002Flifecycle; timeout\u002Fcancellation; OS\u002FCI conditions, retry, cleanup, parallelization, MSTest.Sdk project setup, and MSTESTxxxx. Honor the installed MSTest version. DO NOT USE to design new test cases (code-testing), perform report-only audits, create project files rather than explain MSTest setup, run tests, migrate frameworks, or handle non-MSTest\u002Fnon-.NET code.\n","main","497cc9aba79a931ac6fb8d36a48cc22fe3d6d74b","catalog\u002FTesting\u002FOfficial-DotNet-Test\u002Fskills\u002Fwriting-mstest-tests",41,"https:\u002F\u002Fgithub.com\u002Fmanagedcode\u002Fdotnet-skills","https:\u002F\u002Fskills.managed-code.com","https:\u002F\u002Fgithub.com\u002Fmanagedcode","https:\u002F\u002Fwww.managed-code.com","Open Source Community for .NET Developers: Reliable, Actively Maintained, and Community-Driven. Made in Ukraine 🇺🇦 with ❤️","2026-11-12 19:59:36",{"source":8,"skillName":5,"commands":78,"prompt":88,"zipAvailable":89},[79,82,85],{"tool":80,"command":81},"npx","npx skills add managedcode\u002Fdotnet-skills --skill writing-mstest-tests",{"tool":83,"command":84},"bunx","bunx skills add managedcode\u002Fdotnet-skills --skill writing-mstest-tests",{"tool":86,"command":87},"pnpm","pnpm dlx skills add managedcode\u002Fdotnet-skills --skill writing-mstest-tests","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fmanagedcode\u002Fdotnet-skills\u002Fblob\u002Fmain\u002Fcatalog\u002FTesting\u002FOfficial-DotNet-Test\u002Fskills\u002Fwriting-mstest-tests\u002FSKILL.md",true,[91,97,103,107,111,115,119,123,127,131,135,141,145,149,153,157,161,165,169,173,177,181,185,189,193,197,201,205,209,213,217],{"path":92,"resourceType":93,"resourceTypeDesc":94,"sizeBytes":95,"sourceHtmlUrl":96},".DS_Store","OTHER","其他",6148,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002Finstagram\u002F.DS_Store",{"path":98,"resourceType":99,"resourceTypeDesc":100,"sizeBytes":101,"sourceHtmlUrl":102},"manifest.json","REFERENCE","参考文档",144,"https:\u002F\u002Fgithub.com\u002Fmanagedcode\u002Fdotnet-skills\u002Fblob\u002Fmain\u002Fcatalog\u002FTesting\u002FOfficial-DotNet-Test\u002Fskills\u002Fwriting-mstest-tests\u002Fmanifest.json",{"path":104,"resourceType":99,"resourceTypeDesc":100,"sizeBytes":105,"sourceHtmlUrl":106},"references\u002Faccount_types.md",3297,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002Finstagram\u002Freferences\u002Faccount_types.md",{"path":108,"resourceType":99,"resourceTypeDesc":100,"sizeBytes":109,"sourceHtmlUrl":110},"references\u002Fadvanced-mstest-patterns.md",4369,"https:\u002F\u002Fgithub.com\u002Fmanagedcode\u002Fdotnet-skills\u002Fblob\u002Fmain\u002Fcatalog\u002FTesting\u002FOfficial-DotNet-Test\u002Fskills\u002Fwriting-mstest-tests\u002Freferences\u002Fadvanced-mstest-patterns.md",{"path":112,"resourceType":99,"resourceTypeDesc":100,"sizeBytes":113,"sourceHtmlUrl":114},"references\u002Fgraph_api.md",6886,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002Finstagram\u002Freferences\u002Fgraph_api.md",{"path":116,"resourceType":99,"resourceTypeDesc":100,"sizeBytes":117,"sourceHtmlUrl":118},"references\u002Fpermissions.md",3176,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002Finstagram\u002Freferences\u002Fpermissions.md",{"path":120,"resourceType":99,"resourceTypeDesc":100,"sizeBytes":121,"sourceHtmlUrl":122},"references\u002Fpublishing_guide.md",4983,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002Finstagram\u002Freferences\u002Fpublishing_guide.md",{"path":124,"resourceType":99,"resourceTypeDesc":100,"sizeBytes":125,"sourceHtmlUrl":126},"references\u002Frate_limits.md",3109,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002Finstagram\u002Freferences\u002Frate_limits.md",{"path":128,"resourceType":99,"resourceTypeDesc":100,"sizeBytes":129,"sourceHtmlUrl":130},"references\u002Fschema.md",11412,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002Finstagram\u002Freferences\u002Fschema.md",{"path":132,"resourceType":99,"resourceTypeDesc":100,"sizeBytes":133,"sourceHtmlUrl":134},"references\u002Fsetup_walkthrough.md",4153,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002Finstagram\u002Freferences\u002Fsetup_walkthrough.md",{"path":136,"resourceType":137,"resourceTypeDesc":138,"sizeBytes":139,"sourceHtmlUrl":140},"scripts\u002Faccount_setup.py","SCRIPT","脚本",7576,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002Finstagram\u002Fscripts\u002Faccount_setup.py",{"path":142,"resourceType":137,"resourceTypeDesc":138,"sizeBytes":143,"sourceHtmlUrl":144},"scripts\u002Fanalyze.py",7382,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002Finstagram\u002Fscripts\u002Fanalyze.py",{"path":146,"resourceType":137,"resourceTypeDesc":138,"sizeBytes":147,"sourceHtmlUrl":148},"scripts\u002Fapi_client.py",17069,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002Finstagram\u002Fscripts\u002Fapi_client.py",{"path":150,"resourceType":137,"resourceTypeDesc":138,"sizeBytes":151,"sourceHtmlUrl":152},"scripts\u002Fauth.py",15401,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002Finstagram\u002Fscripts\u002Fauth.py",{"path":154,"resourceType":137,"resourceTypeDesc":138,"sizeBytes":155,"sourceHtmlUrl":156},"scripts\u002Fcomments.py",5456,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002Finstagram\u002Fscripts\u002Fcomments.py",{"path":158,"resourceType":137,"resourceTypeDesc":138,"sizeBytes":159,"sourceHtmlUrl":160},"scripts\u002Fconfig.py",4372,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002Finstagram\u002Fscripts\u002Fconfig.py",{"path":162,"resourceType":137,"resourceTypeDesc":138,"sizeBytes":163,"sourceHtmlUrl":164},"scripts\u002Fdb.py",19654,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002Finstagram\u002Fscripts\u002Fdb.py",{"path":166,"resourceType":137,"resourceTypeDesc":138,"sizeBytes":167,"sourceHtmlUrl":168},"scripts\u002Fexport.py",5191,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002Finstagram\u002Fscripts\u002Fexport.py",{"path":170,"resourceType":137,"resourceTypeDesc":138,"sizeBytes":171,"sourceHtmlUrl":172},"scripts\u002Fgovernance.py",9190,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002Finstagram\u002Fscripts\u002Fgovernance.py",{"path":174,"resourceType":137,"resourceTypeDesc":138,"sizeBytes":175,"sourceHtmlUrl":176},"scripts\u002Fhashtags.py",3520,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002Finstagram\u002Fscripts\u002Fhashtags.py",{"path":178,"resourceType":137,"resourceTypeDesc":138,"sizeBytes":179,"sourceHtmlUrl":180},"scripts\u002Finsights.py",6284,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002Finstagram\u002Fscripts\u002Finsights.py",{"path":182,"resourceType":137,"resourceTypeDesc":138,"sizeBytes":183,"sourceHtmlUrl":184},"scripts\u002Fmedia.py",1972,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002Finstagram\u002Fscripts\u002Fmedia.py",{"path":186,"resourceType":137,"resourceTypeDesc":138,"sizeBytes":187,"sourceHtmlUrl":188},"scripts\u002Fmessages.py",3290,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002Finstagram\u002Fscripts\u002Fmessages.py",{"path":190,"resourceType":137,"resourceTypeDesc":138,"sizeBytes":191,"sourceHtmlUrl":192},"scripts\u002Fprofile.py",1669,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002Finstagram\u002Fscripts\u002Fprofile.py",{"path":194,"resourceType":137,"resourceTypeDesc":138,"sizeBytes":195,"sourceHtmlUrl":196},"scripts\u002Fpublish.py",15128,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002Finstagram\u002Fscripts\u002Fpublish.py",{"path":198,"resourceType":137,"resourceTypeDesc":138,"sizeBytes":199,"sourceHtmlUrl":200},"scripts\u002Frequirements.txt",80,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002Finstagram\u002Fscripts\u002Frequirements.txt",{"path":202,"resourceType":137,"resourceTypeDesc":138,"sizeBytes":203,"sourceHtmlUrl":204},"scripts\u002Frun_all.py",6752,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002Finstagram\u002Fscripts\u002Frun_all.py",{"path":206,"resourceType":137,"resourceTypeDesc":138,"sizeBytes":207,"sourceHtmlUrl":208},"scripts\u002Fschedule.py",7477,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002Finstagram\u002Fscripts\u002Fschedule.py",{"path":210,"resourceType":137,"resourceTypeDesc":138,"sizeBytes":211,"sourceHtmlUrl":212},"scripts\u002Fserve_api.py",7585,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002Finstagram\u002Fscripts\u002Fserve_api.py",{"path":214,"resourceType":137,"resourceTypeDesc":138,"sizeBytes":215,"sourceHtmlUrl":216},"scripts\u002Ftemplates.py",5409,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002Finstagram\u002Fscripts\u002Ftemplates.py",{"path":218,"resourceType":99,"resourceTypeDesc":100,"sizeBytes":219,"sourceHtmlUrl":220},"static\u002Fdashboard.html",10016,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002Finstagram\u002Fstatic\u002Fdashboard.html",[222,252,271,302,312,338],{"skillNo":223,"name":224,"nameZh":6,"description":225,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":226,"categories":227,"keywords":234,"publishedAt":57},"01M6DYQE1Y9FHAQHEDTVFQ3447","xtwitter-scraper","Use XTwitterScraper when a .NET application needs typed access to Xquik's X automation REST API for tweet search, user lookup, posting workflows, extraction jobs, monitors, webhooks, or giveaway draws. USE FOR: integrating the XTwitterScraper NuGet package; reviewing Xquik API client usage; modeling API-key configuration, pagination, binary exports, raw responses, retries, and webhook\u002Fevent flows in .NET. DO NOT USE FOR: unrelated stacks; direct browser automation; generic social-media strategy; or code that does not call Xquik. INVOKES: inspect the repository context, edit targeted files, and run relevant build, test, lint, or validation commands when changes are made.","https:\u002F\u002Fgithub.com\u002Fmanagedcode\u002Fdotnet-skills\u002Fblob\u002Fmain\u002Fcatalog\u002FLibraries\u002FXTwitterScraper\u002Fskills\u002Fxtwitter-scraper\u002FSKILL.md",[228,231],{"categoryNo":229,"categoryName":230,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000010","后端与接口",{"categoryNo":232,"categoryName":233,"taxonomyType":29,"taxonomyTypeDesc":30},"01JBSEEDCAT000000000000030","开发工程师",[235,236,237,52,51,238,239,240,241,242,243,244,245,246,247,44,248,249,250,251],"xtwitter scraper","browser automation","workflows","browser","search","repository","api","Media","api client","access","edit","unrelated","webhooks","social","commands","modeling","webhook",{"skillNo":253,"name":254,"nameZh":6,"description":255,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":256,"categories":257,"keywords":260,"publishedAt":57},"01M6DYQ9S4PE1H6G8MCH9T21HR","sep","Use Sep for high-performance separated-value parsing and writing in .NET, including delimiter inference, explicit parser\u002Fwriter options, and low-allocation row\u002Fcolumn workflows. USE FOR: delimited data needs are performance-sensitive and allocation-aware; project needs explicit control over separator inference, escaping, trimming, and header behavior;. DO NOT USE FOR: unrelated stacks; generic tasks that do not need this specific guidance. INVOKES: inspect the repository context, edit targeted files, and run relevant build, test, lint, or validation commands when changes are made.","https:\u002F\u002Fgithub.com\u002Fmanagedcode\u002Fdotnet-skills\u002Fblob\u002Fmain\u002Fcatalog\u002FLibraries\u002FSep\u002Fskills\u002Fsep\u002FSKILL.md",[258,259],{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":27,"categoryName":28,"taxonomyType":29,"taxonomyTypeDesc":30},[254,32,261,237,262,52,240,263,264,265,245,266,246,44,267,268,269,42,249,270],"performance","tasks","data","parsing","parser","context","do","writer","options","high-performance",{"skillNo":272,"name":273,"nameZh":6,"description":274,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":275,"categories":276,"keywords":277,"publishedAt":57},"01M6DZS2DNEPXCGGF6SSCW6G5V","webgpu-threejs-tsl","Comprehensive guide for developing WebGPU-enabled Three.js applications using TSL (Three.js Shading Language). Covers WebGPU renderer setup, TSL syntax and node materials, compute shaders, post-processing effects, and WGSL integration. Use this skill when working with Three.js WebGPU, TSL shaders, node materials, or GPU compute in Three.js.","https:\u002F\u002Fgithub.com\u002Fmanagedcode\u002Fdotnet-skills\u002Fblob\u002Fmain\u002Fexternal-sources\u002Fupstreams\u002Fwebgpu-claude-skill\u002Fskills\u002Fwebgpu-threejs-tsl\u002FSKILL.md",[],[278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,38],"webgpu","threejs","webgpu threejs tsl","setup","shaders","gpu","integration","applications","js","node","syntax","guide","use","language","three","compute","post","processing","with","renderer","for","materials","wgsl","effects",{"skillNo":303,"name":304,"nameZh":6,"description":305,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":306,"categories":307,"keywords":308,"publishedAt":57},"01M6DZS0BQXW2B56A289XF1X76","roslynk","Use Roslynk for semantic inspection and edits of *.cs, *.razor and *.cshtml solution files.","https:\u002F\u002Fgithub.com\u002Fmanagedcode\u002Fdotnet-skills\u002Fblob\u002Fmain\u002Fexternal-sources\u002Fupstreams\u002Froslynk\u002Fskills\u002Froslynk\u002FSKILL.md",[],[304,290,44,309,310,298,311],"semantic","razor","inspection",{"skillNo":313,"name":314,"nameZh":6,"description":315,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":316,"categories":317,"keywords":318,"publishedAt":57},"01M6DZRW6MEJCVW80K3S4XV60K","system-text-json-net11","Imperative guidance for the System.Text.Json APIs added in .NET 11: the built-in `JsonNamingPolicy.PascalCase` naming policy, and the strongly-typed generic `JsonSerializerOptions.GetTypeInfo` and `JsonSerializerOptions.TryGetTypeInfo` metadata accessors (generic overloads that return a typed `JsonTypeInfo`). USE ONLY when the user is targeting net11.0 or later and needs PascalCase JSON property or dictionary-key names without writing a custom naming policy, a strongly-typed generic `JsonTypeInfo` instead of the non-generic `JsonTypeInfo`, or a no-throw way to probe whether a type's serialization metadata is resolved. DO NOT USE when the target is earlier than net11.0, the requested behavior uses an established pre-net11 naming policy, or the user explicitly selected another JSON library.","https:\u002F\u002Fgithub.com\u002Fmanagedcode\u002Fdotnet-skills\u002Fblob\u002Fmain\u002Fexternal-sources\u002Fupstreams\u002Fdotnet-skills\u002Fplugins\u002Fdotnet11\u002Fskills\u002Fsystem-text-json-net11\u002FSKILL.md",[],[319,320,321,322,32,323,324,325,326,327,328,290,45,329,330,331,267,332,333,334,335,298,336,337,38],"system","json","text","system text json net11","policy","metadata","library","serialization","behavior","user","probe","guidance","later","type","dictionary","naming","targeting","custom","generic",{"skillNo":339,"name":340,"nameZh":6,"description":341,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":342,"categories":343,"keywords":346,"publishedAt":57},"01M6DZRRJP3S662NFSG1RSPQQ7","process-api-net11","Provides guidance on the new System.Diagnostics.Process APIs introduced in .NET 11: Process.Run, Process.RunAndCaptureText, Process.StartAndForget, Process.ReadAllText\u002FBytes\u002FLines, KillOnParentExit, InheritedHandles, and StartDetached. USE FOR: starting, orchestrating, or capturing output from external processes in applications targeting net11.0 or later. DO NOT USE FOR: applications targeting .NET 10 or earlier, or basic pre-.NET 11 Process.Start usage without new APIs.","https:\u002F\u002Fgithub.com\u002Fmanagedcode\u002Fdotnet-skills\u002Fblob\u002Fmain\u002Fexternal-sources\u002Fupstreams\u002Fdotnet-skills\u002Fplugins\u002Fdotnet11\u002Fskills\u002Fprocess-api-net11\u002FSKILL.md",[344,345],{"categoryNo":229,"categoryName":230,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":232,"categoryName":233,"taxonomyType":29,"taxonomyTypeDesc":30},[241,347,348,349,52,350,285,319,290,330,331,267,351,352,353,354,335,298,37],"process","process api net11","diagnostics","start","basic","processes","output","usage"]