[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-dotnet-writing-mstest-tests":3,"mdc-1aro8d-key":31,"related-repo-dotnet-writing-mstest-tests":3439,"related-org-dotnet-writing-mstest-tests":3547},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":11,"stars":19,"repoUrl":20,"updatedAt":21,"license":22,"forks":23,"topics":24,"repo":26,"sourceUrl":29,"mdContent":30},"writing-mstest-tests","write and modernize MSTest unit tests","Write, create, modernize, or fix comprehensive MSTest unit tests with MSTest 3.x\u002F4.x APIs. USE FOR: write, create, review, or modernize MSTest tests and assertions, better MSTest assertion than Assert.IsTrue, replace hard cast with IsInstanceOfType, MSTest assertion APIs (Contains, ContainsSingle, HasCount, IsEmpty, IsNotEmpty, DoesNotContain, AreSame, IsNull, StartsWith, EndsWith, MatchesRegex, IsGreaterThan, IsLessThan, IsInRange), swapped\u002Freversed Assert.AreEqual args (Expected\u002FActual backwards), replace ExpectedException with Assert.Throws, data-driven (DataRow, DynamicData, ValueTuples), lifecycle (TestInitialize, TestCleanup, TestContext), async and cancellation tests, conditional execution\u002Fretry\u002Fcleanup (OSCondition, Retry), parallelization (Parallelize\u002FDoNotParallelize), MSTest.Sdk setup, MSTESTxxxx analyzer fixes. DO NOT USE FOR: test quality audits (use test-anti-patterns), running tests (use run-tests), MSTest version migration (use migrate-mstest skills), xUnit\u002FNUnit\u002FTUnit, or non-.NET languages.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},"dotnet",".NET (Microsoft)","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fdotnet.png",[12,16],{"name":13,"slug":14,"type":15},".NET","net","tag",{"name":17,"slug":18,"type":15},"Testing","testing",4576,"https:\u002F\u002Fgithub.com\u002Fdotnet\u002Fskills","2026-07-12T08:23:45.904983","MIT",332,[25],"agent-skills",{"repoUrl":20,"stars":19,"forks":23,"topics":27,"description":28},[25],"Repository for skills to assist AI coding agents with .NET and C#","https:\u002F\u002Fgithub.com\u002Fdotnet\u002Fskills\u002Ftree\u002FHEAD\u002Fplugins\u002Fdotnet-test\u002Fskills\u002Fwriting-mstest-tests","---\nname: writing-mstest-tests\ndescription: >\n  Write, create, modernize, or fix comprehensive MSTest unit tests with MSTest 3.x\u002F4.x APIs.\n  USE FOR: write, create, review, or modernize MSTest tests and assertions,\n  better MSTest assertion than Assert.IsTrue, replace hard cast with IsInstanceOfType,\n  MSTest assertion APIs (Contains, ContainsSingle, HasCount, IsEmpty, IsNotEmpty, DoesNotContain,\n  AreSame, IsNull, StartsWith, EndsWith, MatchesRegex, IsGreaterThan, IsLessThan, IsInRange),\n  swapped\u002Freversed Assert.AreEqual args (Expected\u002FActual backwards),\n  replace ExpectedException with Assert.Throws,\n  data-driven (DataRow, DynamicData, ValueTuples),\n  lifecycle (TestInitialize, TestCleanup, TestContext),\n  async and cancellation tests, conditional execution\u002Fretry\u002Fcleanup (OSCondition, Retry),\n  parallelization (Parallelize\u002FDoNotParallelize), MSTest.Sdk setup, MSTESTxxxx analyzer fixes.\n  DO NOT USE FOR: test quality audits (use test-anti-patterns),\n  running tests (use run-tests), MSTest version migration (use migrate-mstest skills),\n  xUnit\u002FNUnit\u002FTUnit, or non-.NET languages.\nlicense: MIT\n---\n\n# Writing MSTest Tests\n\nHelp users write effective, modern unit tests with MSTest 3.x\u002F4.x using current APIs and best practices.\n\n## When to Use\n\n- User wants to write new MSTest unit tests\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- **Write new tests from scratch**: Follow the full workflow.\n- **Review and fix existing tests**: Fix only the issues present. Do not add unrelated improvements.\n\n## Workflow\n\n### Step 1: Determine project setup\n\nCheck the test project for MSTest version and configuration:\n\n- If using `MSTest.Sdk` (`\u003CSdk Name=\"MSTest.Sdk\">`): modern setup, all features available\n- If using `MSTest` metapackage: modern setup (MSTest 3.x+)\n- If using `MSTest.TestFramework` + `MSTest.TestAdapter`: check version for feature availability\n\nRecommend MSTest.Sdk or the MSTest metapackage for 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:\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 modern assertion APIs\n\nPick the most specific assertion for each test scenario. More specific assertions produce better failure messages and make the test's intent clear:\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)` |\n| Collection is not empty | `Assert.IsNotEmpty(collection)` |\n| Collection has exactly N items | `Assert.HasCount(N, collection)` |\n| Collection contains an item | `Assert.Contains(item, collection)` |\n| Collection does not contain an item | `Assert.DoesNotContain(item, collection)` |\n| Object is a specific type | `Assert.IsInstanceOfType\u003CT>(value)` |\n| Code throws an exception | `Assert.ThrowsExactly\u003CT>(() => ...)` |\n\nPrefer `Assert` class methods over `StringAssert` or `CollectionAssert` where both exist.\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 -- use `Assert.Throws` instead of `[ExpectedException]`\n\n```csharp\n\u002F\u002F Synchronous\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\n#### Collection assertions\n\n```csharp\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\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\nAssert.Contains(\"expected\", actualString);\nAssert.StartsWith(\"prefix\", actualString);\nAssert.EndsWith(\"suffix\", actualString);\nAssert.MatchesRegex(@\"\\d{3}-\\d{4}\", phoneNumber);\n```\n\n#### Type assertions\n\n```csharp\n\u002F\u002F MSTest 3.x -- out parameter\nAssert.IsInstanceOfType\u003CMyHandler>(result, out var typed);\ntyped.Handle();\n\n\u002F\u002F MSTest 4.x -- returns 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(actual, low, high);\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\nPrefer `ValueTuple` return types over `IEnumerable\u003Cobject[]>` for type safety:\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, 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- **Always initialize in the constructor** -- this enables `readonly` fields and works correctly with nullability analyzers (fields are guaranteed non-null after construction)\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 (MSTest 3.6+)\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\nAlways use `TestContext.CancellationToken` with `[Timeout]`:\n\n```csharp\n[TestMethod]\n[Timeout(5000)]\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\n#### Retry flaky tests (MSTest 3.9+)\n\nUse only for genuinely flaky external dependencies (network, file system), not to paper over race conditions or shared state issues.\n\n```csharp\n[TestMethod]\n[Retry(3)]\npublic void ExternalService_EventuallyResponds() { }\n```\n\n#### Conditional execution (MSTest 3.10+)\n\n```csharp\n[TestMethod]\n[OSCondition(OperatingSystems.Windows)]\npublic void WindowsRegistry_ReadsValue() { }\n\n[TestMethod]\n[CICondition(ConditionMode.Exclude)]\npublic void LocalOnly_InteractiveTest() { }\n```\n\n#### Parallelization\n\n```csharp\n[assembly: Parallelize(Workers = 4, Scope = ExecutionScope.MethodLevel)]\n\n[TestClass]\n[DoNotParallelize]  \u002F\u002F Opt out specific classes\npublic sealed class DatabaseIntegrationTests { }\n```\n\n### Step 8: Fix MSTest analyzer diagnostics (MSTESTxxxx)\n\nThe `MSTest.Analyzers` package reports `MSTESTxxxx` diagnostics during build and in the IDE. The analyzers come in automatically with the modern `MSTest` metapackage and `MSTest.Sdk` (and are bundled with `MSTest.TestFramework` 3.7+); for other setups, reference `MSTest.Analyzers` explicitly. Most rules have an automated code fix (light bulb) in Visual Studio. When fixing one by hand, apply the idiomatic change below rather than suppressing the rule.\n\nWhen asked to \"fix MSTESTxxxx\", look it up in the table of common diagnostics below, apply the fix, and rebuild to confirm the diagnostic is gone. The table is not exhaustive — for any rule it does not list, consult the full reference and apply the documented guidance: \u003Chttps:\u002F\u002Flearn.microsoft.com\u002Fdotnet\u002Fcore\u002Ftesting\u002Fmstest-analyzers\u002Foverview>.\n\n#### Common diagnostics and their fixes\n\n| Rule | Problem | Fix |\n|---|---|---|\n| MSTEST0006 | `[ExpectedException]` used | Replace with `Assert.Throws\u003CT>` \u002F `Assert.ThrowsExactly\u003CT>` (Step 3) |\n| MSTEST0017 | `Assert.AreEqual` args swapped | Put `expected` first, `actual` second |\n| MSTEST0023 | Negated boolean assertion (`Assert.IsTrue(!x)`) | Use `Assert.IsFalse(x)` |\n| MSTEST0025 | Always-false condition asserted | Use `Assert.Fail(\"reason\")` |\n| MSTEST0032 | Always-true assert condition | Remove or correct the assertion |\n| MSTEST0037 | Sub-optimal assert (`IsTrue(x == null)`) | Use the specific assert (`Assert.IsNull`, `HasCount`, etc.) (Step 3) |\n| MSTEST0038 | `Assert.AreSame` on value types | Use `Assert.AreEqual` (value types box to distinct references) |\n| MSTEST0039 | Legacy `Assert.ThrowsException` | Use `Assert.Throws` \u002F `Assert.ThrowsExactly` (+ `Async` variants) |\n| MSTEST0044 | `[DataTestMethod]` used | Replace with `[TestMethod]` (it now supports data rows) |\n| MSTEST0046 | `StringAssert` used | Use the equivalent `Assert` method (`Assert.Contains`, `StartsWith`, ...) |\n| MSTEST0052 | Explicit `DynamicDataSourceType` | Drop it — the source type is inferred |\n| MSTEST0042 \u002F MSTEST0060 | Duplicate `[DataRow]` \u002F `[TestMethod]` | Remove the duplicate attribute |\n| MSTEST0024 | Static `TestContext` field | Make it an instance member (Step 5) |\n| MSTEST0045 \u002F MSTEST0049 \u002F MSTEST0054 | Timeout\u002Ftoken not cooperative | Flow `TestContext.CancellationToken` into the awaited call (Step 6) |\n| MSTEST0036 | Member shadows a base test member | Rename or use `override` instead of `new` |\n| MSTEST0061 | Runtime OS check inside a test | Use `[OSCondition(...)]` (Step 7) |\n| MSTEST0002 \u002F MSTEST0003 \u002F MSTEST0005 \u002F MSTEST0007–0014 | Invalid test class \u002F method \u002F fixture \u002F `TestContext` \u002F data-source layout | Correct the signature named by the rule (e.g. make it public, fix the return type and parameters, add `static` where required) |\n\n#### Tuning which rules are enforced\n\nUse the `MSTestAnalysisMode` MSBuild property (MSTest 3.8+) to control the rule set globally:\n\n```xml\n\u003CPropertyGroup>\n  \u003C!-- None | Default | Recommended | All -->\n  \u003CMSTestAnalysisMode>Recommended\u003C\u002FMSTestAnalysisMode>\n\u003C\u002FPropertyGroup>\n```\n\n- `Recommended` escalates info-level rules to warnings and is the mode most projects should adopt.\n- A handful of rules are completely opt-in (e.g. MSTEST0015, MSTEST0019–0022); enable them per project via `.editorconfig` when you want their convention enforced.\n- Prefer fixing the underlying code over suppressing a diagnostic. Suppress only with a documented justification.\n",{"data":32,"body":33},{"name":4,"description":6,"license":22},{"type":34,"children":35},"root",[36,44,50,57,148,154,217,223,308,314,348,354,361,366,422,427,494,514,614,692,698,703,779,930,936,941,1150,1179,1186,1225,1245,1307,1345,1351,1406,1418,1640,1646,1685,1691,1745,1751,1782,1788,1794,1863,1869,1888,2011,2023,2076,2082,2147,2325,2331,2463,2469,2488,2548,2554,2560,2565,2595,2601,2661,2667,2712,2718,2766,2781,2787,3343,3349,3362,3401,3433],{"type":37,"tag":38,"props":39,"children":40},"element","h1",{"id":4},[41],{"type":42,"value":43},"text","Writing MSTest Tests",{"type":37,"tag":45,"props":46,"children":47},"p",{},[48],{"type":42,"value":49},"Help users write effective, modern unit tests with MSTest 3.x\u002F4.x using current APIs and best practices.",{"type":37,"tag":51,"props":52,"children":54},"h2",{"id":53},"when-to-use",[55],{"type":42,"value":56},"When to Use",{"type":37,"tag":58,"props":59,"children":60},"ul",{},[61,67,72,77,91,96,101,114,135],{"type":37,"tag":62,"props":63,"children":64},"li",{},[65],{"type":42,"value":66},"User wants to write new MSTest unit tests",{"type":37,"tag":62,"props":68,"children":69},{},[70],{"type":42,"value":71},"User wants to improve or modernize existing MSTest tests by implementing concrete fixes",{"type":37,"tag":62,"props":73,"children":74},{},[75],{"type":42,"value":76},"User asks about MSTest assertion APIs, data-driven patterns, or test lifecycle",{"type":37,"tag":62,"props":78,"children":79},{},[80,82,89],{"type":42,"value":81},"User asks to replace ",{"type":37,"tag":83,"props":84,"children":86},"code",{"className":85},[],[87],{"type":42,"value":88},"Assert.IsTrue",{"type":42,"value":90}," with more specific assertions (collections, nulls, types, comparisons)",{"type":37,"tag":62,"props":92,"children":93},{},[94],{"type":42,"value":95},"User asks to replace hard casts with type-checking assertions in tests",{"type":37,"tag":62,"props":97,"children":98},{},[99],{"type":42,"value":100},"User needs help fixing a specific MSTest test bug or failing assertion",{"type":37,"tag":62,"props":102,"children":103},{},[104,106,112],{"type":42,"value":105},"User asks to fix swapped ",{"type":37,"tag":83,"props":107,"children":109},{"className":108},[],[110],{"type":42,"value":111},"Assert.AreEqual",{"type":42,"value":113}," argument order (expected first, actual second)",{"type":37,"tag":62,"props":115,"children":116},{},[117,119,125,127,133],{"type":42,"value":118},"User asks to convert ",{"type":37,"tag":83,"props":120,"children":122},{"className":121},[],[123],{"type":42,"value":124},"DynamicData",{"type":42,"value":126}," from ",{"type":37,"tag":83,"props":128,"children":130},{"className":129},[],[131],{"type":42,"value":132},"IEnumerable\u003Cobject[]>",{"type":42,"value":134}," to ValueTuple-based data",{"type":37,"tag":62,"props":136,"children":137},{},[138,140,146],{"type":42,"value":139},"User asks to fix or understand an MSTest analyzer diagnostic (an ",{"type":37,"tag":83,"props":141,"children":143},{"className":142},[],[144],{"type":42,"value":145},"MSTESTxxxx",{"type":42,"value":147}," warning\u002Ferror)",{"type":37,"tag":51,"props":149,"children":151},{"id":150},"when-not-to-use",[152],{"type":42,"value":153},"When Not to Use",{"type":37,"tag":58,"props":155,"children":156},{},[157,170,183,195,207,212],{"type":37,"tag":62,"props":158,"children":159},{},[160,162,168],{"type":42,"value":161},"User needs a test quality audit, anti-pattern detection, or flaky-test investigation (use ",{"type":37,"tag":83,"props":163,"children":165},{"className":164},[],[166],{"type":42,"value":167},"test-anti-patterns",{"type":42,"value":169},")",{"type":37,"tag":62,"props":171,"children":172},{},[173,175,181],{"type":42,"value":174},"User needs to run or execute tests (use the ",{"type":37,"tag":83,"props":176,"children":178},{"className":177},[],[179],{"type":42,"value":180},"run-tests",{"type":42,"value":182}," skill)",{"type":37,"tag":62,"props":184,"children":185},{},[186,188,194],{"type":42,"value":187},"User needs to upgrade from MSTest v1\u002Fv2 to v3 (use ",{"type":37,"tag":83,"props":189,"children":191},{"className":190},[],[192],{"type":42,"value":193},"migrate-mstest-v1v2-to-v3",{"type":42,"value":169},{"type":37,"tag":62,"props":196,"children":197},{},[198,200,206],{"type":42,"value":199},"User needs to upgrade from MSTest v3 to v4 (use ",{"type":37,"tag":83,"props":201,"children":203},{"className":202},[],[204],{"type":42,"value":205},"migrate-mstest-v3-to-v4",{"type":42,"value":169},{"type":37,"tag":62,"props":208,"children":209},{},[210],{"type":42,"value":211},"User needs CI\u002FCD pipeline configuration",{"type":37,"tag":62,"props":213,"children":214},{},[215],{"type":42,"value":216},"User is using xUnit, NUnit, or TUnit (not MSTest)",{"type":37,"tag":51,"props":218,"children":220},{"id":219},"inputs",[221],{"type":42,"value":222},"Inputs",{"type":37,"tag":224,"props":225,"children":226},"table",{},[227,251],{"type":37,"tag":228,"props":229,"children":230},"thead",{},[231],{"type":37,"tag":232,"props":233,"children":234},"tr",{},[235,241,246],{"type":37,"tag":236,"props":237,"children":238},"th",{},[239],{"type":42,"value":240},"Input",{"type":37,"tag":236,"props":242,"children":243},{},[244],{"type":42,"value":245},"Required",{"type":37,"tag":236,"props":247,"children":248},{},[249],{"type":42,"value":250},"Description",{"type":37,"tag":252,"props":253,"children":254},"tbody",{},[255,274,291],{"type":37,"tag":232,"props":256,"children":257},{},[258,264,269],{"type":37,"tag":259,"props":260,"children":261},"td",{},[262],{"type":42,"value":263},"Code under test",{"type":37,"tag":259,"props":265,"children":266},{},[267],{"type":42,"value":268},"No",{"type":37,"tag":259,"props":270,"children":271},{},[272],{"type":42,"value":273},"The production code to be tested",{"type":37,"tag":232,"props":275,"children":276},{},[277,282,286],{"type":37,"tag":259,"props":278,"children":279},{},[280],{"type":42,"value":281},"Existing test code",{"type":37,"tag":259,"props":283,"children":284},{},[285],{"type":42,"value":268},{"type":37,"tag":259,"props":287,"children":288},{},[289],{"type":42,"value":290},"Current tests to fix, update, or modernize",{"type":37,"tag":232,"props":292,"children":293},{},[294,299,303],{"type":37,"tag":259,"props":295,"children":296},{},[297],{"type":42,"value":298},"Test scenario description",{"type":37,"tag":259,"props":300,"children":301},{},[302],{"type":42,"value":268},{"type":37,"tag":259,"props":304,"children":305},{},[306],{"type":42,"value":307},"What behavior the user wants to test",{"type":37,"tag":51,"props":309,"children":311},{"id":310},"response-guidelines",[312],{"type":42,"value":313},"Response Guidelines",{"type":37,"tag":58,"props":315,"children":316},{},[317,328,338],{"type":37,"tag":62,"props":318,"children":319},{},[320,326],{"type":37,"tag":321,"props":322,"children":323},"strong",{},[324],{"type":42,"value":325},"Specific API or pattern questions",{"type":42,"value":327}," (assertions, data-driven, lifecycle): Jump directly to the relevant workflow step. Do not follow the full workflow.",{"type":37,"tag":62,"props":329,"children":330},{},[331,336],{"type":37,"tag":321,"props":332,"children":333},{},[334],{"type":42,"value":335},"Write new tests from scratch",{"type":42,"value":337},": Follow the full workflow.",{"type":37,"tag":62,"props":339,"children":340},{},[341,346],{"type":37,"tag":321,"props":342,"children":343},{},[344],{"type":42,"value":345},"Review and fix existing tests",{"type":42,"value":347},": Fix only the issues present. Do not add unrelated improvements.",{"type":37,"tag":51,"props":349,"children":351},{"id":350},"workflow",[352],{"type":42,"value":353},"Workflow",{"type":37,"tag":355,"props":356,"children":358},"h3",{"id":357},"step-1-determine-project-setup",[359],{"type":42,"value":360},"Step 1: Determine project setup",{"type":37,"tag":45,"props":362,"children":363},{},[364],{"type":42,"value":365},"Check the test project for MSTest version and configuration:",{"type":37,"tag":58,"props":367,"children":368},{},[369,390,402],{"type":37,"tag":62,"props":370,"children":371},{},[372,374,380,382,388],{"type":42,"value":373},"If using ",{"type":37,"tag":83,"props":375,"children":377},{"className":376},[],[378],{"type":42,"value":379},"MSTest.Sdk",{"type":42,"value":381}," (",{"type":37,"tag":83,"props":383,"children":385},{"className":384},[],[386],{"type":42,"value":387},"\u003CSdk Name=\"MSTest.Sdk\">",{"type":42,"value":389},"): modern setup, all features available",{"type":37,"tag":62,"props":391,"children":392},{},[393,394,400],{"type":42,"value":373},{"type":37,"tag":83,"props":395,"children":397},{"className":396},[],[398],{"type":42,"value":399},"MSTest",{"type":42,"value":401}," metapackage: modern setup (MSTest 3.x+)",{"type":37,"tag":62,"props":403,"children":404},{},[405,406,412,414,420],{"type":42,"value":373},{"type":37,"tag":83,"props":407,"children":409},{"className":408},[],[410],{"type":42,"value":411},"MSTest.TestFramework",{"type":42,"value":413}," + ",{"type":37,"tag":83,"props":415,"children":417},{"className":416},[],[418],{"type":42,"value":419},"MSTest.TestAdapter",{"type":42,"value":421},": check version for feature availability",{"type":37,"tag":45,"props":423,"children":424},{},[425],{"type":42,"value":426},"Recommend MSTest.Sdk or the MSTest metapackage for new projects:",{"type":37,"tag":428,"props":429,"children":434},"pre",{"className":430,"code":431,"language":432,"meta":433,"style":433},"language-xml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\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","xml","",[435],{"type":37,"tag":83,"props":436,"children":437},{"__ignoreMap":433},[438,449,458,467,476,485],{"type":37,"tag":439,"props":440,"children":443},"span",{"class":441,"line":442},"line",1,[444],{"type":37,"tag":439,"props":445,"children":446},{},[447],{"type":42,"value":448},"\u003C!-- Option 1: MSTest SDK (simplest, recommended for new projects) -->\n",{"type":37,"tag":439,"props":450,"children":452},{"class":441,"line":451},2,[453],{"type":37,"tag":439,"props":454,"children":455},{},[456],{"type":42,"value":457},"\u003CProject Sdk=\"MSTest.Sdk\">\n",{"type":37,"tag":439,"props":459,"children":461},{"class":441,"line":460},3,[462],{"type":37,"tag":439,"props":463,"children":464},{},[465],{"type":42,"value":466},"  \u003CPropertyGroup>\n",{"type":37,"tag":439,"props":468,"children":470},{"class":441,"line":469},4,[471],{"type":37,"tag":439,"props":472,"children":473},{},[474],{"type":42,"value":475},"    \u003CTargetFramework>net9.0\u003C\u002FTargetFramework>\n",{"type":37,"tag":439,"props":477,"children":479},{"class":441,"line":478},5,[480],{"type":37,"tag":439,"props":481,"children":482},{},[483],{"type":42,"value":484},"  \u003C\u002FPropertyGroup>\n",{"type":37,"tag":439,"props":486,"children":488},{"class":441,"line":487},6,[489],{"type":37,"tag":439,"props":490,"children":491},{},[492],{"type":42,"value":493},"\u003C\u002FProject>\n",{"type":37,"tag":45,"props":495,"children":496},{},[497,499,504,506,512],{"type":42,"value":498},"When using ",{"type":37,"tag":83,"props":500,"children":502},{"className":501},[],[503],{"type":42,"value":379},{"type":42,"value":505},", put the version in ",{"type":37,"tag":83,"props":507,"children":509},{"className":508},[],[510],{"type":42,"value":511},"global.json",{"type":42,"value":513}," instead of the project file so all test projects get bumped together:",{"type":37,"tag":428,"props":515,"children":519},{"className":516,"code":517,"language":518,"meta":433,"style":433},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"msbuild-sdks\": {\n    \"MSTest.Sdk\": \"3.8.2\"\n  }\n}\n","json",[520],{"type":37,"tag":83,"props":521,"children":522},{"__ignoreMap":433},[523,532,561,598,606],{"type":37,"tag":439,"props":524,"children":525},{"class":441,"line":442},[526],{"type":37,"tag":439,"props":527,"children":529},{"style":528},"--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF",[530],{"type":42,"value":531},"{\n",{"type":37,"tag":439,"props":533,"children":534},{"class":441,"line":451},[535,540,546,551,556],{"type":37,"tag":439,"props":536,"children":537},{"style":528},[538],{"type":42,"value":539},"  \"",{"type":37,"tag":439,"props":541,"children":543},{"style":542},"--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA",[544],{"type":42,"value":545},"msbuild-sdks",{"type":37,"tag":439,"props":547,"children":548},{"style":528},[549],{"type":42,"value":550},"\"",{"type":37,"tag":439,"props":552,"children":553},{"style":528},[554],{"type":42,"value":555},":",{"type":37,"tag":439,"props":557,"children":558},{"style":528},[559],{"type":42,"value":560}," {\n",{"type":37,"tag":439,"props":562,"children":563},{"class":441,"line":460},[564,569,574,578,582,587,593],{"type":37,"tag":439,"props":565,"children":566},{"style":528},[567],{"type":42,"value":568},"    \"",{"type":37,"tag":439,"props":570,"children":572},{"style":571},"--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B",[573],{"type":42,"value":379},{"type":37,"tag":439,"props":575,"children":576},{"style":528},[577],{"type":42,"value":550},{"type":37,"tag":439,"props":579,"children":580},{"style":528},[581],{"type":42,"value":555},{"type":37,"tag":439,"props":583,"children":584},{"style":528},[585],{"type":42,"value":586}," \"",{"type":37,"tag":439,"props":588,"children":590},{"style":589},"--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D",[591],{"type":42,"value":592},"3.8.2",{"type":37,"tag":439,"props":594,"children":595},{"style":528},[596],{"type":42,"value":597},"\"\n",{"type":37,"tag":439,"props":599,"children":600},{"class":441,"line":469},[601],{"type":37,"tag":439,"props":602,"children":603},{"style":528},[604],{"type":42,"value":605},"  }\n",{"type":37,"tag":439,"props":607,"children":608},{"class":441,"line":478},[609],{"type":37,"tag":439,"props":610,"children":611},{"style":528},[612],{"type":42,"value":613},"}\n",{"type":37,"tag":428,"props":615,"children":617},{"className":430,"code":616,"language":432,"meta":433,"style":433},"\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",[618],{"type":37,"tag":83,"props":619,"children":620},{"__ignoreMap":433},[621,629,637,644,651,658,666,675,684],{"type":37,"tag":439,"props":622,"children":623},{"class":441,"line":442},[624],{"type":37,"tag":439,"props":625,"children":626},{},[627],{"type":42,"value":628},"\u003C!-- Option 2: MSTest metapackage -->\n",{"type":37,"tag":439,"props":630,"children":631},{"class":441,"line":451},[632],{"type":37,"tag":439,"props":633,"children":634},{},[635],{"type":42,"value":636},"\u003CProject Sdk=\"Microsoft.NET.Sdk\">\n",{"type":37,"tag":439,"props":638,"children":639},{"class":441,"line":460},[640],{"type":37,"tag":439,"props":641,"children":642},{},[643],{"type":42,"value":466},{"type":37,"tag":439,"props":645,"children":646},{"class":441,"line":469},[647],{"type":37,"tag":439,"props":648,"children":649},{},[650],{"type":42,"value":475},{"type":37,"tag":439,"props":652,"children":653},{"class":441,"line":478},[654],{"type":37,"tag":439,"props":655,"children":656},{},[657],{"type":42,"value":484},{"type":37,"tag":439,"props":659,"children":660},{"class":441,"line":487},[661],{"type":37,"tag":439,"props":662,"children":663},{},[664],{"type":42,"value":665},"  \u003CItemGroup>\n",{"type":37,"tag":439,"props":667,"children":669},{"class":441,"line":668},7,[670],{"type":37,"tag":439,"props":671,"children":672},{},[673],{"type":42,"value":674},"    \u003CPackageReference Include=\"MSTest\" Version=\"3.8.2\" \u002F>\n",{"type":37,"tag":439,"props":676,"children":678},{"class":441,"line":677},8,[679],{"type":37,"tag":439,"props":680,"children":681},{},[682],{"type":42,"value":683},"  \u003C\u002FItemGroup>\n",{"type":37,"tag":439,"props":685,"children":687},{"class":441,"line":686},9,[688],{"type":37,"tag":439,"props":689,"children":690},{},[691],{"type":42,"value":493},{"type":37,"tag":355,"props":693,"children":695},{"id":694},"step-2-write-test-classes-following-conventions",[696],{"type":42,"value":697},"Step 2: Write test classes following conventions",{"type":37,"tag":45,"props":699,"children":700},{},[701],{"type":42,"value":702},"Apply these structural conventions:",{"type":37,"tag":58,"props":704,"children":705},{},[706,724,745,757,768],{"type":37,"tag":62,"props":707,"children":708},{},[709,714,716,722],{"type":37,"tag":321,"props":710,"children":711},{},[712],{"type":42,"value":713},"Seal test classes",{"type":42,"value":715}," with ",{"type":37,"tag":83,"props":717,"children":719},{"className":718},[],[720],{"type":42,"value":721},"sealed",{"type":42,"value":723}," for performance and design clarity",{"type":37,"tag":62,"props":725,"children":726},{},[727,729,735,737,743],{"type":42,"value":728},"Use ",{"type":37,"tag":83,"props":730,"children":732},{"className":731},[],[733],{"type":42,"value":734},"[TestClass]",{"type":42,"value":736}," on the class and ",{"type":37,"tag":83,"props":738,"children":740},{"className":739},[],[741],{"type":42,"value":742},"[TestMethod]",{"type":42,"value":744}," on test methods",{"type":37,"tag":62,"props":746,"children":747},{},[748,750,755],{"type":42,"value":749},"Follow the ",{"type":37,"tag":321,"props":751,"children":752},{},[753],{"type":42,"value":754},"Arrange-Act-Assert",{"type":42,"value":756}," (AAA) pattern",{"type":37,"tag":62,"props":758,"children":759},{},[760,762],{"type":42,"value":761},"Name tests using ",{"type":37,"tag":83,"props":763,"children":765},{"className":764},[],[766],{"type":42,"value":767},"MethodName_Scenario_ExpectedBehavior",{"type":37,"tag":62,"props":769,"children":770},{},[771,773],{"type":42,"value":772},"Use separate test projects with naming convention ",{"type":37,"tag":83,"props":774,"children":776},{"className":775},[],[777],{"type":42,"value":778},"[ProjectName].Tests",{"type":37,"tag":428,"props":780,"children":784},{"className":781,"code":782,"language":783,"meta":433,"style":433},"language-csharp shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","[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","csharp",[785],{"type":37,"tag":83,"props":786,"children":787},{"__ignoreMap":433},[788,796,804,811,819,827,835,843,851,859,869,878,887,895,904,913,922],{"type":37,"tag":439,"props":789,"children":790},{"class":441,"line":442},[791],{"type":37,"tag":439,"props":792,"children":793},{},[794],{"type":42,"value":795},"[TestClass]\n",{"type":37,"tag":439,"props":797,"children":798},{"class":441,"line":451},[799],{"type":37,"tag":439,"props":800,"children":801},{},[802],{"type":42,"value":803},"public sealed class OrderServiceTests\n",{"type":37,"tag":439,"props":805,"children":806},{"class":441,"line":460},[807],{"type":37,"tag":439,"props":808,"children":809},{},[810],{"type":42,"value":531},{"type":37,"tag":439,"props":812,"children":813},{"class":441,"line":469},[814],{"type":37,"tag":439,"props":815,"children":816},{},[817],{"type":42,"value":818},"    [TestMethod]\n",{"type":37,"tag":439,"props":820,"children":821},{"class":441,"line":478},[822],{"type":37,"tag":439,"props":823,"children":824},{},[825],{"type":42,"value":826},"    public void CalculateTotal_WithDiscount_ReturnsReducedPrice()\n",{"type":37,"tag":439,"props":828,"children":829},{"class":441,"line":487},[830],{"type":37,"tag":439,"props":831,"children":832},{},[833],{"type":42,"value":834},"    {\n",{"type":37,"tag":439,"props":836,"children":837},{"class":441,"line":668},[838],{"type":37,"tag":439,"props":839,"children":840},{},[841],{"type":42,"value":842},"        \u002F\u002F Arrange\n",{"type":37,"tag":439,"props":844,"children":845},{"class":441,"line":677},[846],{"type":37,"tag":439,"props":847,"children":848},{},[849],{"type":42,"value":850},"        var service = new OrderService();\n",{"type":37,"tag":439,"props":852,"children":853},{"class":441,"line":686},[854],{"type":37,"tag":439,"props":855,"children":856},{},[857],{"type":42,"value":858},"        var order = new Order { Price = 100m, DiscountPercent = 10 };\n",{"type":37,"tag":439,"props":860,"children":862},{"class":441,"line":861},10,[863],{"type":37,"tag":439,"props":864,"children":866},{"emptyLinePlaceholder":865},true,[867],{"type":42,"value":868},"\n",{"type":37,"tag":439,"props":870,"children":872},{"class":441,"line":871},11,[873],{"type":37,"tag":439,"props":874,"children":875},{},[876],{"type":42,"value":877},"        \u002F\u002F Act\n",{"type":37,"tag":439,"props":879,"children":881},{"class":441,"line":880},12,[882],{"type":37,"tag":439,"props":883,"children":884},{},[885],{"type":42,"value":886},"        var total = service.CalculateTotal(order);\n",{"type":37,"tag":439,"props":888,"children":890},{"class":441,"line":889},13,[891],{"type":37,"tag":439,"props":892,"children":893},{"emptyLinePlaceholder":865},[894],{"type":42,"value":868},{"type":37,"tag":439,"props":896,"children":898},{"class":441,"line":897},14,[899],{"type":37,"tag":439,"props":900,"children":901},{},[902],{"type":42,"value":903},"        \u002F\u002F Assert\n",{"type":37,"tag":439,"props":905,"children":907},{"class":441,"line":906},15,[908],{"type":37,"tag":439,"props":909,"children":910},{},[911],{"type":42,"value":912},"        Assert.AreEqual(90m, total);\n",{"type":37,"tag":439,"props":914,"children":916},{"class":441,"line":915},16,[917],{"type":37,"tag":439,"props":918,"children":919},{},[920],{"type":42,"value":921},"    }\n",{"type":37,"tag":439,"props":923,"children":925},{"class":441,"line":924},17,[926],{"type":37,"tag":439,"props":927,"children":928},{},[929],{"type":42,"value":613},{"type":37,"tag":355,"props":931,"children":933},{"id":932},"step-3-use-modern-assertion-apis",[934],{"type":42,"value":935},"Step 3: Use modern assertion APIs",{"type":37,"tag":45,"props":937,"children":938},{},[939],{"type":42,"value":940},"Pick the most specific assertion for each test scenario. More specific assertions produce better failure messages and make the test's intent clear:",{"type":37,"tag":224,"props":942,"children":943},{},[944,960],{"type":37,"tag":228,"props":945,"children":946},{},[947],{"type":37,"tag":232,"props":948,"children":949},{},[950,955],{"type":37,"tag":236,"props":951,"children":952},{},[953],{"type":42,"value":954},"What you are testing",{"type":37,"tag":236,"props":956,"children":957},{},[958],{"type":42,"value":959},"Assertion",{"type":37,"tag":252,"props":961,"children":962},{},[963,980,997,1014,1031,1048,1065,1082,1099,1116,1133],{"type":37,"tag":232,"props":964,"children":965},{},[966,971],{"type":37,"tag":259,"props":967,"children":968},{},[969],{"type":42,"value":970},"Two values are equal",{"type":37,"tag":259,"props":972,"children":973},{},[974],{"type":37,"tag":83,"props":975,"children":977},{"className":976},[],[978],{"type":42,"value":979},"Assert.AreEqual(expected, actual)",{"type":37,"tag":232,"props":981,"children":982},{},[983,988],{"type":37,"tag":259,"props":984,"children":985},{},[986],{"type":42,"value":987},"Same object instance (reference identity)",{"type":37,"tag":259,"props":989,"children":990},{},[991],{"type":37,"tag":83,"props":992,"children":994},{"className":993},[],[995],{"type":42,"value":996},"Assert.AreSame(expected, actual)",{"type":37,"tag":232,"props":998,"children":999},{},[1000,1005],{"type":37,"tag":259,"props":1001,"children":1002},{},[1003],{"type":42,"value":1004},"Value is null",{"type":37,"tag":259,"props":1006,"children":1007},{},[1008],{"type":37,"tag":83,"props":1009,"children":1011},{"className":1010},[],[1012],{"type":42,"value":1013},"Assert.IsNull(value)",{"type":37,"tag":232,"props":1015,"children":1016},{},[1017,1022],{"type":37,"tag":259,"props":1018,"children":1019},{},[1020],{"type":42,"value":1021},"Value is not null",{"type":37,"tag":259,"props":1023,"children":1024},{},[1025],{"type":37,"tag":83,"props":1026,"children":1028},{"className":1027},[],[1029],{"type":42,"value":1030},"Assert.IsNotNull(value)",{"type":37,"tag":232,"props":1032,"children":1033},{},[1034,1039],{"type":37,"tag":259,"props":1035,"children":1036},{},[1037],{"type":42,"value":1038},"Collection is empty",{"type":37,"tag":259,"props":1040,"children":1041},{},[1042],{"type":37,"tag":83,"props":1043,"children":1045},{"className":1044},[],[1046],{"type":42,"value":1047},"Assert.IsEmpty(collection)",{"type":37,"tag":232,"props":1049,"children":1050},{},[1051,1056],{"type":37,"tag":259,"props":1052,"children":1053},{},[1054],{"type":42,"value":1055},"Collection is not empty",{"type":37,"tag":259,"props":1057,"children":1058},{},[1059],{"type":37,"tag":83,"props":1060,"children":1062},{"className":1061},[],[1063],{"type":42,"value":1064},"Assert.IsNotEmpty(collection)",{"type":37,"tag":232,"props":1066,"children":1067},{},[1068,1073],{"type":37,"tag":259,"props":1069,"children":1070},{},[1071],{"type":42,"value":1072},"Collection has exactly N items",{"type":37,"tag":259,"props":1074,"children":1075},{},[1076],{"type":37,"tag":83,"props":1077,"children":1079},{"className":1078},[],[1080],{"type":42,"value":1081},"Assert.HasCount(N, collection)",{"type":37,"tag":232,"props":1083,"children":1084},{},[1085,1090],{"type":37,"tag":259,"props":1086,"children":1087},{},[1088],{"type":42,"value":1089},"Collection contains an item",{"type":37,"tag":259,"props":1091,"children":1092},{},[1093],{"type":37,"tag":83,"props":1094,"children":1096},{"className":1095},[],[1097],{"type":42,"value":1098},"Assert.Contains(item, collection)",{"type":37,"tag":232,"props":1100,"children":1101},{},[1102,1107],{"type":37,"tag":259,"props":1103,"children":1104},{},[1105],{"type":42,"value":1106},"Collection does not contain an item",{"type":37,"tag":259,"props":1108,"children":1109},{},[1110],{"type":37,"tag":83,"props":1111,"children":1113},{"className":1112},[],[1114],{"type":42,"value":1115},"Assert.DoesNotContain(item, collection)",{"type":37,"tag":232,"props":1117,"children":1118},{},[1119,1124],{"type":37,"tag":259,"props":1120,"children":1121},{},[1122],{"type":42,"value":1123},"Object is a specific type",{"type":37,"tag":259,"props":1125,"children":1126},{},[1127],{"type":37,"tag":83,"props":1128,"children":1130},{"className":1129},[],[1131],{"type":42,"value":1132},"Assert.IsInstanceOfType\u003CT>(value)",{"type":37,"tag":232,"props":1134,"children":1135},{},[1136,1141],{"type":37,"tag":259,"props":1137,"children":1138},{},[1139],{"type":42,"value":1140},"Code throws an exception",{"type":37,"tag":259,"props":1142,"children":1143},{},[1144],{"type":37,"tag":83,"props":1145,"children":1147},{"className":1146},[],[1148],{"type":42,"value":1149},"Assert.ThrowsExactly\u003CT>(() => ...)",{"type":37,"tag":45,"props":1151,"children":1152},{},[1153,1155,1161,1163,1169,1171,1177],{"type":42,"value":1154},"Prefer ",{"type":37,"tag":83,"props":1156,"children":1158},{"className":1157},[],[1159],{"type":42,"value":1160},"Assert",{"type":42,"value":1162}," class methods over ",{"type":37,"tag":83,"props":1164,"children":1166},{"className":1165},[],[1167],{"type":42,"value":1168},"StringAssert",{"type":42,"value":1170}," or ",{"type":37,"tag":83,"props":1172,"children":1174},{"className":1173},[],[1175],{"type":42,"value":1176},"CollectionAssert",{"type":42,"value":1178}," where both exist.",{"type":37,"tag":1180,"props":1181,"children":1183},"h4",{"id":1182},"equality-null-and-reference-checks",[1184],{"type":42,"value":1185},"Equality, null, and reference checks",{"type":37,"tag":428,"props":1187,"children":1189},{"className":781,"code":1188,"language":783,"meta":433,"style":433},"Assert.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",[1190],{"type":37,"tag":83,"props":1191,"children":1192},{"__ignoreMap":433},[1193,1201,1209,1217],{"type":37,"tag":439,"props":1194,"children":1195},{"class":441,"line":442},[1196],{"type":37,"tag":439,"props":1197,"children":1198},{},[1199],{"type":42,"value":1200},"Assert.AreEqual(expected, actual);      \u002F\u002F Value equality\n",{"type":37,"tag":439,"props":1202,"children":1203},{"class":441,"line":451},[1204],{"type":37,"tag":439,"props":1205,"children":1206},{},[1207],{"type":42,"value":1208},"Assert.AreSame(expected, actual);       \u002F\u002F Reference equality -- same object instance\n",{"type":37,"tag":439,"props":1210,"children":1211},{"class":441,"line":460},[1212],{"type":37,"tag":439,"props":1213,"children":1214},{},[1215],{"type":42,"value":1216},"Assert.IsNull(value);\n",{"type":37,"tag":439,"props":1218,"children":1219},{"class":441,"line":469},[1220],{"type":37,"tag":439,"props":1221,"children":1222},{},[1223],{"type":42,"value":1224},"Assert.IsNotNull(value);\n",{"type":37,"tag":1180,"props":1226,"children":1228},{"id":1227},"exception-testing-use-assertthrows-instead-of-expectedexception",[1229,1231,1237,1239],{"type":42,"value":1230},"Exception testing -- use ",{"type":37,"tag":83,"props":1232,"children":1234},{"className":1233},[],[1235],{"type":42,"value":1236},"Assert.Throws",{"type":42,"value":1238}," instead of ",{"type":37,"tag":83,"props":1240,"children":1242},{"className":1241},[],[1243],{"type":42,"value":1244},"[ExpectedException]",{"type":37,"tag":428,"props":1246,"children":1248},{"className":781,"code":1247,"language":783,"meta":433,"style":433},"\u002F\u002F Synchronous\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",[1249],{"type":37,"tag":83,"props":1250,"children":1251},{"__ignoreMap":433},[1252,1260,1268,1276,1283,1291,1299],{"type":37,"tag":439,"props":1253,"children":1254},{"class":441,"line":442},[1255],{"type":37,"tag":439,"props":1256,"children":1257},{},[1258],{"type":42,"value":1259},"\u002F\u002F Synchronous\n",{"type":37,"tag":439,"props":1261,"children":1262},{"class":441,"line":451},[1263],{"type":37,"tag":439,"props":1264,"children":1265},{},[1266],{"type":42,"value":1267},"var ex = Assert.ThrowsExactly\u003CArgumentNullException>(() => service.Process(null));\n",{"type":37,"tag":439,"props":1269,"children":1270},{"class":441,"line":460},[1271],{"type":37,"tag":439,"props":1272,"children":1273},{},[1274],{"type":42,"value":1275},"Assert.AreEqual(\"input\", ex.ParamName);\n",{"type":37,"tag":439,"props":1277,"children":1278},{"class":441,"line":469},[1279],{"type":37,"tag":439,"props":1280,"children":1281},{"emptyLinePlaceholder":865},[1282],{"type":42,"value":868},{"type":37,"tag":439,"props":1284,"children":1285},{"class":441,"line":478},[1286],{"type":37,"tag":439,"props":1287,"children":1288},{},[1289],{"type":42,"value":1290},"\u002F\u002F Async\n",{"type":37,"tag":439,"props":1292,"children":1293},{"class":441,"line":487},[1294],{"type":37,"tag":439,"props":1295,"children":1296},{},[1297],{"type":42,"value":1298},"var ex = await Assert.ThrowsExactlyAsync\u003CInvalidOperationException>(\n",{"type":37,"tag":439,"props":1300,"children":1301},{"class":441,"line":668},[1302],{"type":37,"tag":439,"props":1303,"children":1304},{},[1305],{"type":42,"value":1306},"    async () => await service.ProcessAsync(null));\n",{"type":37,"tag":58,"props":1308,"children":1309},{},[1310,1329],{"type":37,"tag":62,"props":1311,"children":1312},{},[1313,1319,1321,1327],{"type":37,"tag":83,"props":1314,"children":1316},{"className":1315},[],[1317],{"type":42,"value":1318},"Assert.Throws\u003CT>",{"type":42,"value":1320}," matches ",{"type":37,"tag":83,"props":1322,"children":1324},{"className":1323},[],[1325],{"type":42,"value":1326},"T",{"type":42,"value":1328}," or any derived type",{"type":37,"tag":62,"props":1330,"children":1331},{},[1332,1338,1340],{"type":37,"tag":83,"props":1333,"children":1335},{"className":1334},[],[1336],{"type":42,"value":1337},"Assert.ThrowsExactly\u003CT>",{"type":42,"value":1339}," matches only the exact type ",{"type":37,"tag":83,"props":1341,"children":1343},{"className":1342},[],[1344],{"type":42,"value":1326},{"type":37,"tag":1180,"props":1346,"children":1348},{"id":1347},"collection-assertions",[1349],{"type":42,"value":1350},"Collection assertions",{"type":37,"tag":428,"props":1352,"children":1354},{"className":781,"code":1353,"language":783,"meta":433,"style":433},"Assert.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",[1355],{"type":37,"tag":83,"props":1356,"children":1357},{"__ignoreMap":433},[1358,1366,1374,1382,1390,1398],{"type":37,"tag":439,"props":1359,"children":1360},{"class":441,"line":442},[1361],{"type":37,"tag":439,"props":1362,"children":1363},{},[1364],{"type":42,"value":1365},"Assert.Contains(expectedItem, collection);\n",{"type":37,"tag":439,"props":1367,"children":1368},{"class":441,"line":451},[1369],{"type":37,"tag":439,"props":1370,"children":1371},{},[1372],{"type":42,"value":1373},"Assert.DoesNotContain(unexpectedItem, collection);\n",{"type":37,"tag":439,"props":1375,"children":1376},{"class":441,"line":460},[1377],{"type":37,"tag":439,"props":1378,"children":1379},{},[1380],{"type":42,"value":1381},"var single = Assert.ContainsSingle(collection);  \u002F\u002F Returns the single element\n",{"type":37,"tag":439,"props":1383,"children":1384},{"class":441,"line":469},[1385],{"type":37,"tag":439,"props":1386,"children":1387},{},[1388],{"type":42,"value":1389},"Assert.HasCount(3, collection);\n",{"type":37,"tag":439,"props":1391,"children":1392},{"class":441,"line":478},[1393],{"type":37,"tag":439,"props":1394,"children":1395},{},[1396],{"type":42,"value":1397},"Assert.IsEmpty(collection);\n",{"type":37,"tag":439,"props":1399,"children":1400},{"class":441,"line":487},[1401],{"type":37,"tag":439,"props":1402,"children":1403},{},[1404],{"type":42,"value":1405},"Assert.IsNotEmpty(collection);\n",{"type":37,"tag":45,"props":1407,"children":1408},{},[1409,1411,1416],{"type":42,"value":1410},"Replace generic ",{"type":37,"tag":83,"props":1412,"children":1414},{"className":1413},[],[1415],{"type":42,"value":88},{"type":42,"value":1417}," with specialized assertions -- they give better failure messages:",{"type":37,"tag":224,"props":1419,"children":1420},{},[1421,1437],{"type":37,"tag":228,"props":1422,"children":1423},{},[1424],{"type":37,"tag":232,"props":1425,"children":1426},{},[1427,1432],{"type":37,"tag":236,"props":1428,"children":1429},{},[1430],{"type":42,"value":1431},"Instead of",{"type":37,"tag":236,"props":1433,"children":1434},{},[1435],{"type":42,"value":1436},"Use",{"type":37,"tag":252,"props":1438,"children":1439},{},[1440,1461,1482,1503,1524,1545,1570,1591,1619],{"type":37,"tag":232,"props":1441,"children":1442},{},[1443,1452],{"type":37,"tag":259,"props":1444,"children":1445},{},[1446],{"type":37,"tag":83,"props":1447,"children":1449},{"className":1448},[],[1450],{"type":42,"value":1451},"Assert.IsTrue(list.Count > 0)",{"type":37,"tag":259,"props":1453,"children":1454},{},[1455],{"type":37,"tag":83,"props":1456,"children":1458},{"className":1457},[],[1459],{"type":42,"value":1460},"Assert.IsNotEmpty(list)",{"type":37,"tag":232,"props":1462,"children":1463},{},[1464,1473],{"type":37,"tag":259,"props":1465,"children":1466},{},[1467],{"type":37,"tag":83,"props":1468,"children":1470},{"className":1469},[],[1471],{"type":42,"value":1472},"Assert.IsTrue(list.Count == 0)",{"type":37,"tag":259,"props":1474,"children":1475},{},[1476],{"type":37,"tag":83,"props":1477,"children":1479},{"className":1478},[],[1480],{"type":42,"value":1481},"Assert.IsEmpty(list)",{"type":37,"tag":232,"props":1483,"children":1484},{},[1485,1494],{"type":37,"tag":259,"props":1486,"children":1487},{},[1488],{"type":37,"tag":83,"props":1489,"children":1491},{"className":1490},[],[1492],{"type":42,"value":1493},"Assert.IsTrue(list.Count() == 3)",{"type":37,"tag":259,"props":1495,"children":1496},{},[1497],{"type":37,"tag":83,"props":1498,"children":1500},{"className":1499},[],[1501],{"type":42,"value":1502},"Assert.HasCount(3, list)",{"type":37,"tag":232,"props":1504,"children":1505},{},[1506,1515],{"type":37,"tag":259,"props":1507,"children":1508},{},[1509],{"type":37,"tag":83,"props":1510,"children":1512},{"className":1511},[],[1513],{"type":42,"value":1514},"Assert.IsTrue(x != null)",{"type":37,"tag":259,"props":1516,"children":1517},{},[1518],{"type":37,"tag":83,"props":1519,"children":1521},{"className":1520},[],[1522],{"type":42,"value":1523},"Assert.IsNotNull(x)",{"type":37,"tag":232,"props":1525,"children":1526},{},[1527,1536],{"type":37,"tag":259,"props":1528,"children":1529},{},[1530],{"type":37,"tag":83,"props":1531,"children":1533},{"className":1532},[],[1534],{"type":42,"value":1535},"Assert.IsTrue(x == null)",{"type":37,"tag":259,"props":1537,"children":1538},{},[1539],{"type":37,"tag":83,"props":1540,"children":1542},{"className":1541},[],[1543],{"type":42,"value":1544},"Assert.IsNull(x)",{"type":37,"tag":232,"props":1546,"children":1547},{},[1548,1559],{"type":37,"tag":259,"props":1549,"children":1550},{},[1551,1557],{"type":37,"tag":83,"props":1552,"children":1554},{"className":1553},[],[1555],{"type":42,"value":1556},"Assert.AreEqual(a, b)",{"type":42,"value":1558}," for same instance",{"type":37,"tag":259,"props":1560,"children":1561},{},[1562,1568],{"type":37,"tag":83,"props":1563,"children":1565},{"className":1564},[],[1566],{"type":42,"value":1567},"Assert.AreSame(a, b)",{"type":42,"value":1569}," -- reference identity",{"type":37,"tag":232,"props":1571,"children":1572},{},[1573,1582],{"type":37,"tag":259,"props":1574,"children":1575},{},[1576],{"type":37,"tag":83,"props":1577,"children":1579},{"className":1578},[],[1580],{"type":42,"value":1581},"Assert.IsTrue(!list.Contains(item))",{"type":37,"tag":259,"props":1583,"children":1584},{},[1585],{"type":37,"tag":83,"props":1586,"children":1588},{"className":1587},[],[1589],{"type":42,"value":1590},"Assert.DoesNotContain(item, list)",{"type":37,"tag":232,"props":1592,"children":1593},{},[1594,1610],{"type":37,"tag":259,"props":1595,"children":1596},{},[1597,1603,1604],{"type":37,"tag":83,"props":1598,"children":1600},{"className":1599},[],[1601],{"type":42,"value":1602},"list.Single(predicate)",{"type":42,"value":413},{"type":37,"tag":83,"props":1605,"children":1607},{"className":1606},[],[1608],{"type":42,"value":1609},"Assert.IsNotNull",{"type":37,"tag":259,"props":1611,"children":1612},{},[1613],{"type":37,"tag":83,"props":1614,"children":1616},{"className":1615},[],[1617],{"type":42,"value":1618},"Assert.ContainsSingle(list)",{"type":37,"tag":232,"props":1620,"children":1621},{},[1622,1631],{"type":37,"tag":259,"props":1623,"children":1624},{},[1625],{"type":37,"tag":83,"props":1626,"children":1628},{"className":1627},[],[1629],{"type":42,"value":1630},"Assert.IsTrue(list.Contains(item))",{"type":37,"tag":259,"props":1632,"children":1633},{},[1634],{"type":37,"tag":83,"props":1635,"children":1637},{"className":1636},[],[1638],{"type":42,"value":1639},"Assert.Contains(item, list)",{"type":37,"tag":1180,"props":1641,"children":1643},{"id":1642},"string-assertions",[1644],{"type":42,"value":1645},"String assertions",{"type":37,"tag":428,"props":1647,"children":1649},{"className":781,"code":1648,"language":783,"meta":433,"style":433},"Assert.Contains(\"expected\", actualString);\nAssert.StartsWith(\"prefix\", actualString);\nAssert.EndsWith(\"suffix\", actualString);\nAssert.MatchesRegex(@\"\\d{3}-\\d{4}\", phoneNumber);\n",[1650],{"type":37,"tag":83,"props":1651,"children":1652},{"__ignoreMap":433},[1653,1661,1669,1677],{"type":37,"tag":439,"props":1654,"children":1655},{"class":441,"line":442},[1656],{"type":37,"tag":439,"props":1657,"children":1658},{},[1659],{"type":42,"value":1660},"Assert.Contains(\"expected\", actualString);\n",{"type":37,"tag":439,"props":1662,"children":1663},{"class":441,"line":451},[1664],{"type":37,"tag":439,"props":1665,"children":1666},{},[1667],{"type":42,"value":1668},"Assert.StartsWith(\"prefix\", actualString);\n",{"type":37,"tag":439,"props":1670,"children":1671},{"class":441,"line":460},[1672],{"type":37,"tag":439,"props":1673,"children":1674},{},[1675],{"type":42,"value":1676},"Assert.EndsWith(\"suffix\", actualString);\n",{"type":37,"tag":439,"props":1678,"children":1679},{"class":441,"line":469},[1680],{"type":37,"tag":439,"props":1681,"children":1682},{},[1683],{"type":42,"value":1684},"Assert.MatchesRegex(@\"\\d{3}-\\d{4}\", phoneNumber);\n",{"type":37,"tag":1180,"props":1686,"children":1688},{"id":1687},"type-assertions",[1689],{"type":42,"value":1690},"Type assertions",{"type":37,"tag":428,"props":1692,"children":1694},{"className":781,"code":1693,"language":783,"meta":433,"style":433},"\u002F\u002F MSTest 3.x -- out parameter\nAssert.IsInstanceOfType\u003CMyHandler>(result, out var typed);\ntyped.Handle();\n\n\u002F\u002F MSTest 4.x -- returns directly\nvar typed = Assert.IsInstanceOfType\u003CMyHandler>(result);\n",[1695],{"type":37,"tag":83,"props":1696,"children":1697},{"__ignoreMap":433},[1698,1706,1714,1722,1729,1737],{"type":37,"tag":439,"props":1699,"children":1700},{"class":441,"line":442},[1701],{"type":37,"tag":439,"props":1702,"children":1703},{},[1704],{"type":42,"value":1705},"\u002F\u002F MSTest 3.x -- out parameter\n",{"type":37,"tag":439,"props":1707,"children":1708},{"class":441,"line":451},[1709],{"type":37,"tag":439,"props":1710,"children":1711},{},[1712],{"type":42,"value":1713},"Assert.IsInstanceOfType\u003CMyHandler>(result, out var typed);\n",{"type":37,"tag":439,"props":1715,"children":1716},{"class":441,"line":460},[1717],{"type":37,"tag":439,"props":1718,"children":1719},{},[1720],{"type":42,"value":1721},"typed.Handle();\n",{"type":37,"tag":439,"props":1723,"children":1724},{"class":441,"line":469},[1725],{"type":37,"tag":439,"props":1726,"children":1727},{"emptyLinePlaceholder":865},[1728],{"type":42,"value":868},{"type":37,"tag":439,"props":1730,"children":1731},{"class":441,"line":478},[1732],{"type":37,"tag":439,"props":1733,"children":1734},{},[1735],{"type":42,"value":1736},"\u002F\u002F MSTest 4.x -- returns directly\n",{"type":37,"tag":439,"props":1738,"children":1739},{"class":441,"line":487},[1740],{"type":37,"tag":439,"props":1741,"children":1742},{},[1743],{"type":42,"value":1744},"var typed = Assert.IsInstanceOfType\u003CMyHandler>(result);\n",{"type":37,"tag":1180,"props":1746,"children":1748},{"id":1747},"comparison-assertions",[1749],{"type":42,"value":1750},"Comparison assertions",{"type":37,"tag":428,"props":1752,"children":1754},{"className":781,"code":1753,"language":783,"meta":433,"style":433},"Assert.IsGreaterThan(lowerBound, actual);\nAssert.IsLessThan(upperBound, actual);\nAssert.IsInRange(actual, low, high);\n",[1755],{"type":37,"tag":83,"props":1756,"children":1757},{"__ignoreMap":433},[1758,1766,1774],{"type":37,"tag":439,"props":1759,"children":1760},{"class":441,"line":442},[1761],{"type":37,"tag":439,"props":1762,"children":1763},{},[1764],{"type":42,"value":1765},"Assert.IsGreaterThan(lowerBound, actual);\n",{"type":37,"tag":439,"props":1767,"children":1768},{"class":441,"line":451},[1769],{"type":37,"tag":439,"props":1770,"children":1771},{},[1772],{"type":42,"value":1773},"Assert.IsLessThan(upperBound, actual);\n",{"type":37,"tag":439,"props":1775,"children":1776},{"class":441,"line":460},[1777],{"type":37,"tag":439,"props":1778,"children":1779},{},[1780],{"type":42,"value":1781},"Assert.IsInRange(actual, low, high);\n",{"type":37,"tag":355,"props":1783,"children":1785},{"id":1784},"step-4-use-data-driven-tests-for-multiple-inputs",[1786],{"type":42,"value":1787},"Step 4: Use data-driven tests for multiple inputs",{"type":37,"tag":1180,"props":1789,"children":1791},{"id":1790},"datarow-for-inline-values",[1792],{"type":42,"value":1793},"DataRow for inline values",{"type":37,"tag":428,"props":1795,"children":1797},{"className":781,"code":1796,"language":783,"meta":433,"style":433},"[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",[1798],{"type":37,"tag":83,"props":1799,"children":1800},{"__ignoreMap":433},[1801,1809,1817,1825,1833,1841,1848,1856],{"type":37,"tag":439,"props":1802,"children":1803},{"class":441,"line":442},[1804],{"type":37,"tag":439,"props":1805,"children":1806},{},[1807],{"type":42,"value":1808},"[TestMethod]\n",{"type":37,"tag":439,"props":1810,"children":1811},{"class":441,"line":451},[1812],{"type":37,"tag":439,"props":1813,"children":1814},{},[1815],{"type":42,"value":1816},"[DataRow(1, 2, 3)]\n",{"type":37,"tag":439,"props":1818,"children":1819},{"class":441,"line":460},[1820],{"type":37,"tag":439,"props":1821,"children":1822},{},[1823],{"type":42,"value":1824},"[DataRow(0, 0, 0, DisplayName = \"Zeros\")]\n",{"type":37,"tag":439,"props":1826,"children":1827},{"class":441,"line":469},[1828],{"type":37,"tag":439,"props":1829,"children":1830},{},[1831],{"type":42,"value":1832},"[DataRow(-1, 1, 0)]\n",{"type":37,"tag":439,"props":1834,"children":1835},{"class":441,"line":478},[1836],{"type":37,"tag":439,"props":1837,"children":1838},{},[1839],{"type":42,"value":1840},"public void Add_ReturnsExpectedSum(int a, int b, int expected)\n",{"type":37,"tag":439,"props":1842,"children":1843},{"class":441,"line":487},[1844],{"type":37,"tag":439,"props":1845,"children":1846},{},[1847],{"type":42,"value":531},{"type":37,"tag":439,"props":1849,"children":1850},{"class":441,"line":668},[1851],{"type":37,"tag":439,"props":1852,"children":1853},{},[1854],{"type":42,"value":1855},"    Assert.AreEqual(expected, Calculator.Add(a, b));\n",{"type":37,"tag":439,"props":1857,"children":1858},{"class":441,"line":677},[1859],{"type":37,"tag":439,"props":1860,"children":1861},{},[1862],{"type":42,"value":613},{"type":37,"tag":1180,"props":1864,"children":1866},{"id":1865},"dynamicdata-with-valuetuples-preferred-for-complex-data",[1867],{"type":42,"value":1868},"DynamicData with ValueTuples (preferred for complex data)",{"type":37,"tag":45,"props":1870,"children":1871},{},[1872,1873,1879,1881,1886],{"type":42,"value":1154},{"type":37,"tag":83,"props":1874,"children":1876},{"className":1875},[],[1877],{"type":42,"value":1878},"ValueTuple",{"type":42,"value":1880}," return types over ",{"type":37,"tag":83,"props":1882,"children":1884},{"className":1883},[],[1885],{"type":42,"value":132},{"type":42,"value":1887}," for type safety:",{"type":37,"tag":428,"props":1889,"children":1891},{"className":781,"code":1890,"language":783,"meta":433,"style":433},"[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",[1892],{"type":37,"tag":83,"props":1893,"children":1894},{"__ignoreMap":433},[1895,1902,1910,1918,1925,1933,1941,1948,1955,1963,1971,1979,1987,1995,2003],{"type":37,"tag":439,"props":1896,"children":1897},{"class":441,"line":442},[1898],{"type":37,"tag":439,"props":1899,"children":1900},{},[1901],{"type":42,"value":1808},{"type":37,"tag":439,"props":1903,"children":1904},{"class":441,"line":451},[1905],{"type":37,"tag":439,"props":1906,"children":1907},{},[1908],{"type":42,"value":1909},"[DynamicData(nameof(DiscountTestData))]\n",{"type":37,"tag":439,"props":1911,"children":1912},{"class":441,"line":460},[1913],{"type":37,"tag":439,"props":1914,"children":1915},{},[1916],{"type":42,"value":1917},"public void ApplyDiscount_ReturnsExpectedPrice(decimal price, int percent, decimal expected)\n",{"type":37,"tag":439,"props":1919,"children":1920},{"class":441,"line":469},[1921],{"type":37,"tag":439,"props":1922,"children":1923},{},[1924],{"type":42,"value":531},{"type":37,"tag":439,"props":1926,"children":1927},{"class":441,"line":478},[1928],{"type":37,"tag":439,"props":1929,"children":1930},{},[1931],{"type":42,"value":1932},"    var result = PriceCalculator.ApplyDiscount(price, percent);\n",{"type":37,"tag":439,"props":1934,"children":1935},{"class":441,"line":487},[1936],{"type":37,"tag":439,"props":1937,"children":1938},{},[1939],{"type":42,"value":1940},"    Assert.AreEqual(expected, result);\n",{"type":37,"tag":439,"props":1942,"children":1943},{"class":441,"line":668},[1944],{"type":37,"tag":439,"props":1945,"children":1946},{},[1947],{"type":42,"value":613},{"type":37,"tag":439,"props":1949,"children":1950},{"class":441,"line":677},[1951],{"type":37,"tag":439,"props":1952,"children":1953},{"emptyLinePlaceholder":865},[1954],{"type":42,"value":868},{"type":37,"tag":439,"props":1956,"children":1957},{"class":441,"line":686},[1958],{"type":37,"tag":439,"props":1959,"children":1960},{},[1961],{"type":42,"value":1962},"\u002F\u002F ValueTuple -- preferred (MSTest 3.7+)\n",{"type":37,"tag":439,"props":1964,"children":1965},{"class":441,"line":861},[1966],{"type":37,"tag":439,"props":1967,"children":1968},{},[1969],{"type":42,"value":1970},"public static IEnumerable\u003C(decimal price, int percent, decimal expected)> DiscountTestData =>\n",{"type":37,"tag":439,"props":1972,"children":1973},{"class":441,"line":871},[1974],{"type":37,"tag":439,"props":1975,"children":1976},{},[1977],{"type":42,"value":1978},"[\n",{"type":37,"tag":439,"props":1980,"children":1981},{"class":441,"line":880},[1982],{"type":37,"tag":439,"props":1983,"children":1984},{},[1985],{"type":42,"value":1986},"    (100m, 10, 90m),\n",{"type":37,"tag":439,"props":1988,"children":1989},{"class":441,"line":889},[1990],{"type":37,"tag":439,"props":1991,"children":1992},{},[1993],{"type":42,"value":1994},"    (200m, 25, 150m),\n",{"type":37,"tag":439,"props":1996,"children":1997},{"class":441,"line":897},[1998],{"type":37,"tag":439,"props":1999,"children":2000},{},[2001],{"type":42,"value":2002},"    (50m, 0, 50m),\n",{"type":37,"tag":439,"props":2004,"children":2005},{"class":441,"line":906},[2006],{"type":37,"tag":439,"props":2007,"children":2008},{},[2009],{"type":42,"value":2010},"];\n",{"type":37,"tag":45,"props":2012,"children":2013},{},[2014,2016,2022],{"type":42,"value":2015},"When you need metadata per test case, use ",{"type":37,"tag":83,"props":2017,"children":2019},{"className":2018},[],[2020],{"type":42,"value":2021},"TestDataRow\u003CT>",{"type":42,"value":555},{"type":37,"tag":428,"props":2024,"children":2026},{"className":781,"code":2025,"language":783,"meta":433,"style":433},"public 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",[2027],{"type":37,"tag":83,"props":2028,"children":2029},{"__ignoreMap":433},[2030,2038,2045,2053,2061,2069],{"type":37,"tag":439,"props":2031,"children":2032},{"class":441,"line":442},[2033],{"type":37,"tag":439,"props":2034,"children":2035},{},[2036],{"type":42,"value":2037},"public static IEnumerable\u003CTestDataRow\u003C(decimal price, int percent, decimal expected)>> DiscountTestDataWithMetadata =>\n",{"type":37,"tag":439,"props":2039,"children":2040},{"class":441,"line":451},[2041],{"type":37,"tag":439,"props":2042,"children":2043},{},[2044],{"type":42,"value":1978},{"type":37,"tag":439,"props":2046,"children":2047},{"class":441,"line":460},[2048],{"type":37,"tag":439,"props":2049,"children":2050},{},[2051],{"type":42,"value":2052},"    new((100m, 10, 90m)) { DisplayName = \"10% discount\" },\n",{"type":37,"tag":439,"props":2054,"children":2055},{"class":441,"line":469},[2056],{"type":37,"tag":439,"props":2057,"children":2058},{},[2059],{"type":42,"value":2060},"    new((200m, 25, 150m)) { DisplayName = \"25% discount\" },\n",{"type":37,"tag":439,"props":2062,"children":2063},{"class":441,"line":478},[2064],{"type":37,"tag":439,"props":2065,"children":2066},{},[2067],{"type":42,"value":2068},"    new((50m, 0, 50m)) { DisplayName = \"No discount\" },\n",{"type":37,"tag":439,"props":2070,"children":2071},{"class":441,"line":487},[2072],{"type":37,"tag":439,"props":2073,"children":2074},{},[2075],{"type":42,"value":2010},{"type":37,"tag":355,"props":2077,"children":2079},{"id":2078},"step-5-handle-test-lifecycle-correctly",[2080],{"type":42,"value":2081},"Step 5: Handle test lifecycle correctly",{"type":37,"tag":58,"props":2083,"children":2084},{},[2085,2103,2122,2134],{"type":37,"tag":62,"props":2086,"children":2087},{},[2088,2093,2095,2101],{"type":37,"tag":321,"props":2089,"children":2090},{},[2091],{"type":42,"value":2092},"Always initialize in the constructor",{"type":42,"value":2094}," -- this enables ",{"type":37,"tag":83,"props":2096,"children":2098},{"className":2097},[],[2099],{"type":42,"value":2100},"readonly",{"type":42,"value":2102}," fields and works correctly with nullability analyzers (fields are guaranteed non-null after construction)",{"type":37,"tag":62,"props":2104,"children":2105},{},[2106,2107,2113,2115,2120],{"type":42,"value":728},{"type":37,"tag":83,"props":2108,"children":2110},{"className":2109},[],[2111],{"type":42,"value":2112},"[TestInitialize]",{"type":42,"value":2114}," ",{"type":37,"tag":321,"props":2116,"children":2117},{},[2118],{"type":42,"value":2119},"only",{"type":42,"value":2121}," for async initialization, combined with the constructor for sync parts",{"type":37,"tag":62,"props":2123,"children":2124},{},[2125,2126,2132],{"type":42,"value":728},{"type":37,"tag":83,"props":2127,"children":2129},{"className":2128},[],[2130],{"type":42,"value":2131},"[TestCleanup]",{"type":42,"value":2133}," for cleanup that must run even on failure",{"type":37,"tag":62,"props":2135,"children":2136},{},[2137,2139,2145],{"type":42,"value":2138},"Inject ",{"type":37,"tag":83,"props":2140,"children":2142},{"className":2141},[],[2143],{"type":42,"value":2144},"TestContext",{"type":42,"value":2146}," via constructor (MSTest 3.6+)",{"type":37,"tag":428,"props":2148,"children":2150},{"className":781,"code":2149,"language":783,"meta":433,"style":433},"[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",[2151],{"type":37,"tag":83,"props":2152,"children":2153},{"__ignoreMap":433},[2154,2161,2169,2176,2184,2192,2199,2207,2214,2222,2230,2237,2244,2252,2260,2267,2275,2283,2291,2299,2308,2317],{"type":37,"tag":439,"props":2155,"children":2156},{"class":441,"line":442},[2157],{"type":37,"tag":439,"props":2158,"children":2159},{},[2160],{"type":42,"value":795},{"type":37,"tag":439,"props":2162,"children":2163},{"class":441,"line":451},[2164],{"type":37,"tag":439,"props":2165,"children":2166},{},[2167],{"type":42,"value":2168},"public sealed class RepositoryTests\n",{"type":37,"tag":439,"props":2170,"children":2171},{"class":441,"line":460},[2172],{"type":37,"tag":439,"props":2173,"children":2174},{},[2175],{"type":42,"value":531},{"type":37,"tag":439,"props":2177,"children":2178},{"class":441,"line":469},[2179],{"type":37,"tag":439,"props":2180,"children":2181},{},[2182],{"type":42,"value":2183},"    private readonly TestContext _testContext;\n",{"type":37,"tag":439,"props":2185,"children":2186},{"class":441,"line":478},[2187],{"type":37,"tag":439,"props":2188,"children":2189},{},[2190],{"type":42,"value":2191},"    private readonly FakeDatabase _db;  \u002F\u002F readonly -- guaranteed by constructor\n",{"type":37,"tag":439,"props":2193,"children":2194},{"class":441,"line":487},[2195],{"type":37,"tag":439,"props":2196,"children":2197},{"emptyLinePlaceholder":865},[2198],{"type":42,"value":868},{"type":37,"tag":439,"props":2200,"children":2201},{"class":441,"line":668},[2202],{"type":37,"tag":439,"props":2203,"children":2204},{},[2205],{"type":42,"value":2206},"    public RepositoryTests(TestContext testContext)\n",{"type":37,"tag":439,"props":2208,"children":2209},{"class":441,"line":677},[2210],{"type":37,"tag":439,"props":2211,"children":2212},{},[2213],{"type":42,"value":834},{"type":37,"tag":439,"props":2215,"children":2216},{"class":441,"line":686},[2217],{"type":37,"tag":439,"props":2218,"children":2219},{},[2220],{"type":42,"value":2221},"        _testContext = testContext;\n",{"type":37,"tag":439,"props":2223,"children":2224},{"class":441,"line":861},[2225],{"type":37,"tag":439,"props":2226,"children":2227},{},[2228],{"type":42,"value":2229},"        _db = new FakeDatabase();  \u002F\u002F sync init in ctor\n",{"type":37,"tag":439,"props":2231,"children":2232},{"class":441,"line":871},[2233],{"type":37,"tag":439,"props":2234,"children":2235},{},[2236],{"type":42,"value":921},{"type":37,"tag":439,"props":2238,"children":2239},{"class":441,"line":880},[2240],{"type":37,"tag":439,"props":2241,"children":2242},{"emptyLinePlaceholder":865},[2243],{"type":42,"value":868},{"type":37,"tag":439,"props":2245,"children":2246},{"class":441,"line":889},[2247],{"type":37,"tag":439,"props":2248,"children":2249},{},[2250],{"type":42,"value":2251},"    [TestInitialize]\n",{"type":37,"tag":439,"props":2253,"children":2254},{"class":441,"line":897},[2255],{"type":37,"tag":439,"props":2256,"children":2257},{},[2258],{"type":42,"value":2259},"    public async Task InitAsync()\n",{"type":37,"tag":439,"props":2261,"children":2262},{"class":441,"line":906},[2263],{"type":37,"tag":439,"props":2264,"children":2265},{},[2266],{"type":42,"value":834},{"type":37,"tag":439,"props":2268,"children":2269},{"class":441,"line":915},[2270],{"type":37,"tag":439,"props":2271,"children":2272},{},[2273],{"type":42,"value":2274},"        \u002F\u002F Use TestInitialize ONLY for async setup\n",{"type":37,"tag":439,"props":2276,"children":2277},{"class":441,"line":924},[2278],{"type":37,"tag":439,"props":2279,"children":2280},{},[2281],{"type":42,"value":2282},"        await _db.SeedAsync();\n",{"type":37,"tag":439,"props":2284,"children":2286},{"class":441,"line":2285},18,[2287],{"type":37,"tag":439,"props":2288,"children":2289},{},[2290],{"type":42,"value":921},{"type":37,"tag":439,"props":2292,"children":2294},{"class":441,"line":2293},19,[2295],{"type":37,"tag":439,"props":2296,"children":2297},{"emptyLinePlaceholder":865},[2298],{"type":42,"value":868},{"type":37,"tag":439,"props":2300,"children":2302},{"class":441,"line":2301},20,[2303],{"type":37,"tag":439,"props":2304,"children":2305},{},[2306],{"type":42,"value":2307},"    [TestCleanup]\n",{"type":37,"tag":439,"props":2309,"children":2311},{"class":441,"line":2310},21,[2312],{"type":37,"tag":439,"props":2313,"children":2314},{},[2315],{"type":42,"value":2316},"    public void Cleanup() => _db.Reset();\n",{"type":37,"tag":439,"props":2318,"children":2320},{"class":441,"line":2319},22,[2321],{"type":37,"tag":439,"props":2322,"children":2323},{},[2324],{"type":42,"value":613},{"type":37,"tag":1180,"props":2326,"children":2328},{"id":2327},"execution-order",[2329],{"type":42,"value":2330},"Execution order",{"type":37,"tag":2332,"props":2333,"children":2334},"ol",{},[2335,2346,2357,2413,2418,2443,2453],{"type":37,"tag":62,"props":2336,"children":2337},{},[2338,2344],{"type":37,"tag":83,"props":2339,"children":2341},{"className":2340},[],[2342],{"type":42,"value":2343},"[AssemblyInitialize]",{"type":42,"value":2345}," -- once per assembly",{"type":37,"tag":62,"props":2347,"children":2348},{},[2349,2355],{"type":37,"tag":83,"props":2350,"children":2352},{"className":2351},[],[2353],{"type":42,"value":2354},"[ClassInitialize]",{"type":42,"value":2356}," -- once per class",{"type":37,"tag":62,"props":2358,"children":2359},{},[2360,2362],{"type":42,"value":2361},"Per test:\n",{"type":37,"tag":58,"props":2363,"children":2364},{},[2365,2389],{"type":37,"tag":62,"props":2366,"children":2367},{},[2368,2370,2375,2377,2382,2384],{"type":42,"value":2369},"With ",{"type":37,"tag":83,"props":2371,"children":2373},{"className":2372},[],[2374],{"type":42,"value":2144},{"type":42,"value":2376}," property injection: Constructor -> set ",{"type":37,"tag":83,"props":2378,"children":2380},{"className":2379},[],[2381],{"type":42,"value":2144},{"type":42,"value":2383}," property -> ",{"type":37,"tag":83,"props":2385,"children":2387},{"className":2386},[],[2388],{"type":42,"value":2112},{"type":37,"tag":62,"props":2390,"children":2391},{},[2392,2394,2399,2401,2406,2408],{"type":42,"value":2393},"With constructor injection of ",{"type":37,"tag":83,"props":2395,"children":2397},{"className":2396},[],[2398],{"type":42,"value":2144},{"type":42,"value":2400},": Constructor (receives ",{"type":37,"tag":83,"props":2402,"children":2404},{"className":2403},[],[2405],{"type":42,"value":2144},{"type":42,"value":2407},") -> ",{"type":37,"tag":83,"props":2409,"children":2411},{"className":2410},[],[2412],{"type":42,"value":2112},{"type":37,"tag":62,"props":2414,"children":2415},{},[2416],{"type":42,"value":2417},"Test method",{"type":37,"tag":62,"props":2419,"children":2420},{},[2421,2426,2428,2434,2435,2441],{"type":37,"tag":83,"props":2422,"children":2424},{"className":2423},[],[2425],{"type":42,"value":2131},{"type":42,"value":2427}," -> ",{"type":37,"tag":83,"props":2429,"children":2431},{"className":2430},[],[2432],{"type":42,"value":2433},"DisposeAsync",{"type":42,"value":2427},{"type":37,"tag":83,"props":2436,"children":2438},{"className":2437},[],[2439],{"type":42,"value":2440},"Dispose",{"type":42,"value":2442}," -- per test",{"type":37,"tag":62,"props":2444,"children":2445},{},[2446,2452],{"type":37,"tag":83,"props":2447,"children":2449},{"className":2448},[],[2450],{"type":42,"value":2451},"[ClassCleanup]",{"type":42,"value":2356},{"type":37,"tag":62,"props":2454,"children":2455},{},[2456,2462],{"type":37,"tag":83,"props":2457,"children":2459},{"className":2458},[],[2460],{"type":42,"value":2461},"[AssemblyCleanup]",{"type":42,"value":2345},{"type":37,"tag":355,"props":2464,"children":2466},{"id":2465},"step-6-apply-cancellation-and-timeout-patterns",[2467],{"type":42,"value":2468},"Step 6: Apply cancellation and timeout patterns",{"type":37,"tag":45,"props":2470,"children":2471},{},[2472,2474,2480,2481,2487],{"type":42,"value":2473},"Always use ",{"type":37,"tag":83,"props":2475,"children":2477},{"className":2476},[],[2478],{"type":42,"value":2479},"TestContext.CancellationToken",{"type":42,"value":715},{"type":37,"tag":83,"props":2482,"children":2484},{"className":2483},[],[2485],{"type":42,"value":2486},"[Timeout]",{"type":42,"value":555},{"type":37,"tag":428,"props":2489,"children":2491},{"className":781,"code":2490,"language":783,"meta":433,"style":433},"[TestMethod]\n[Timeout(5000)]\npublic async Task FetchData_ReturnsWithinTimeout()\n{\n    var result = await _client.GetDataAsync(_testContext.CancellationToken);\n    Assert.IsNotNull(result);\n}\n",[2492],{"type":37,"tag":83,"props":2493,"children":2494},{"__ignoreMap":433},[2495,2502,2510,2518,2525,2533,2541],{"type":37,"tag":439,"props":2496,"children":2497},{"class":441,"line":442},[2498],{"type":37,"tag":439,"props":2499,"children":2500},{},[2501],{"type":42,"value":1808},{"type":37,"tag":439,"props":2503,"children":2504},{"class":441,"line":451},[2505],{"type":37,"tag":439,"props":2506,"children":2507},{},[2508],{"type":42,"value":2509},"[Timeout(5000)]\n",{"type":37,"tag":439,"props":2511,"children":2512},{"class":441,"line":460},[2513],{"type":37,"tag":439,"props":2514,"children":2515},{},[2516],{"type":42,"value":2517},"public async Task FetchData_ReturnsWithinTimeout()\n",{"type":37,"tag":439,"props":2519,"children":2520},{"class":441,"line":469},[2521],{"type":37,"tag":439,"props":2522,"children":2523},{},[2524],{"type":42,"value":531},{"type":37,"tag":439,"props":2526,"children":2527},{"class":441,"line":478},[2528],{"type":37,"tag":439,"props":2529,"children":2530},{},[2531],{"type":42,"value":2532},"    var result = await _client.GetDataAsync(_testContext.CancellationToken);\n",{"type":37,"tag":439,"props":2534,"children":2535},{"class":441,"line":487},[2536],{"type":37,"tag":439,"props":2537,"children":2538},{},[2539],{"type":42,"value":2540},"    Assert.IsNotNull(result);\n",{"type":37,"tag":439,"props":2542,"children":2543},{"class":441,"line":668},[2544],{"type":37,"tag":439,"props":2545,"children":2546},{},[2547],{"type":42,"value":613},{"type":37,"tag":355,"props":2549,"children":2551},{"id":2550},"step-7-use-advanced-features-where-appropriate",[2552],{"type":42,"value":2553},"Step 7: Use advanced features where appropriate",{"type":37,"tag":1180,"props":2555,"children":2557},{"id":2556},"retry-flaky-tests-mstest-39",[2558],{"type":42,"value":2559},"Retry flaky tests (MSTest 3.9+)",{"type":37,"tag":45,"props":2561,"children":2562},{},[2563],{"type":42,"value":2564},"Use only for genuinely flaky external dependencies (network, file system), not to paper over race conditions or shared state issues.",{"type":37,"tag":428,"props":2566,"children":2568},{"className":781,"code":2567,"language":783,"meta":433,"style":433},"[TestMethod]\n[Retry(3)]\npublic void ExternalService_EventuallyResponds() { }\n",[2569],{"type":37,"tag":83,"props":2570,"children":2571},{"__ignoreMap":433},[2572,2579,2587],{"type":37,"tag":439,"props":2573,"children":2574},{"class":441,"line":442},[2575],{"type":37,"tag":439,"props":2576,"children":2577},{},[2578],{"type":42,"value":1808},{"type":37,"tag":439,"props":2580,"children":2581},{"class":441,"line":451},[2582],{"type":37,"tag":439,"props":2583,"children":2584},{},[2585],{"type":42,"value":2586},"[Retry(3)]\n",{"type":37,"tag":439,"props":2588,"children":2589},{"class":441,"line":460},[2590],{"type":37,"tag":439,"props":2591,"children":2592},{},[2593],{"type":42,"value":2594},"public void ExternalService_EventuallyResponds() { }\n",{"type":37,"tag":1180,"props":2596,"children":2598},{"id":2597},"conditional-execution-mstest-310",[2599],{"type":42,"value":2600},"Conditional execution (MSTest 3.10+)",{"type":37,"tag":428,"props":2602,"children":2604},{"className":781,"code":2603,"language":783,"meta":433,"style":433},"[TestMethod]\n[OSCondition(OperatingSystems.Windows)]\npublic void WindowsRegistry_ReadsValue() { }\n\n[TestMethod]\n[CICondition(ConditionMode.Exclude)]\npublic void LocalOnly_InteractiveTest() { }\n",[2605],{"type":37,"tag":83,"props":2606,"children":2607},{"__ignoreMap":433},[2608,2615,2623,2631,2638,2645,2653],{"type":37,"tag":439,"props":2609,"children":2610},{"class":441,"line":442},[2611],{"type":37,"tag":439,"props":2612,"children":2613},{},[2614],{"type":42,"value":1808},{"type":37,"tag":439,"props":2616,"children":2617},{"class":441,"line":451},[2618],{"type":37,"tag":439,"props":2619,"children":2620},{},[2621],{"type":42,"value":2622},"[OSCondition(OperatingSystems.Windows)]\n",{"type":37,"tag":439,"props":2624,"children":2625},{"class":441,"line":460},[2626],{"type":37,"tag":439,"props":2627,"children":2628},{},[2629],{"type":42,"value":2630},"public void WindowsRegistry_ReadsValue() { }\n",{"type":37,"tag":439,"props":2632,"children":2633},{"class":441,"line":469},[2634],{"type":37,"tag":439,"props":2635,"children":2636},{"emptyLinePlaceholder":865},[2637],{"type":42,"value":868},{"type":37,"tag":439,"props":2639,"children":2640},{"class":441,"line":478},[2641],{"type":37,"tag":439,"props":2642,"children":2643},{},[2644],{"type":42,"value":1808},{"type":37,"tag":439,"props":2646,"children":2647},{"class":441,"line":487},[2648],{"type":37,"tag":439,"props":2649,"children":2650},{},[2651],{"type":42,"value":2652},"[CICondition(ConditionMode.Exclude)]\n",{"type":37,"tag":439,"props":2654,"children":2655},{"class":441,"line":668},[2656],{"type":37,"tag":439,"props":2657,"children":2658},{},[2659],{"type":42,"value":2660},"public void LocalOnly_InteractiveTest() { }\n",{"type":37,"tag":1180,"props":2662,"children":2664},{"id":2663},"parallelization",[2665],{"type":42,"value":2666},"Parallelization",{"type":37,"tag":428,"props":2668,"children":2670},{"className":781,"code":2669,"language":783,"meta":433,"style":433},"[assembly: Parallelize(Workers = 4, Scope = ExecutionScope.MethodLevel)]\n\n[TestClass]\n[DoNotParallelize]  \u002F\u002F Opt out specific classes\npublic sealed class DatabaseIntegrationTests { }\n",[2671],{"type":37,"tag":83,"props":2672,"children":2673},{"__ignoreMap":433},[2674,2682,2689,2696,2704],{"type":37,"tag":439,"props":2675,"children":2676},{"class":441,"line":442},[2677],{"type":37,"tag":439,"props":2678,"children":2679},{},[2680],{"type":42,"value":2681},"[assembly: Parallelize(Workers = 4, Scope = ExecutionScope.MethodLevel)]\n",{"type":37,"tag":439,"props":2683,"children":2684},{"class":441,"line":451},[2685],{"type":37,"tag":439,"props":2686,"children":2687},{"emptyLinePlaceholder":865},[2688],{"type":42,"value":868},{"type":37,"tag":439,"props":2690,"children":2691},{"class":441,"line":460},[2692],{"type":37,"tag":439,"props":2693,"children":2694},{},[2695],{"type":42,"value":795},{"type":37,"tag":439,"props":2697,"children":2698},{"class":441,"line":469},[2699],{"type":37,"tag":439,"props":2700,"children":2701},{},[2702],{"type":42,"value":2703},"[DoNotParallelize]  \u002F\u002F Opt out specific classes\n",{"type":37,"tag":439,"props":2705,"children":2706},{"class":441,"line":478},[2707],{"type":37,"tag":439,"props":2708,"children":2709},{},[2710],{"type":42,"value":2711},"public sealed class DatabaseIntegrationTests { }\n",{"type":37,"tag":355,"props":2713,"children":2715},{"id":2714},"step-8-fix-mstest-analyzer-diagnostics-mstestxxxx",[2716],{"type":42,"value":2717},"Step 8: Fix MSTest analyzer diagnostics (MSTESTxxxx)",{"type":37,"tag":45,"props":2719,"children":2720},{},[2721,2723,2729,2731,2736,2738,2743,2745,2750,2752,2757,2759,2764],{"type":42,"value":2722},"The ",{"type":37,"tag":83,"props":2724,"children":2726},{"className":2725},[],[2727],{"type":42,"value":2728},"MSTest.Analyzers",{"type":42,"value":2730}," package reports ",{"type":37,"tag":83,"props":2732,"children":2734},{"className":2733},[],[2735],{"type":42,"value":145},{"type":42,"value":2737}," diagnostics during build and in the IDE. The analyzers come in automatically with the modern ",{"type":37,"tag":83,"props":2739,"children":2741},{"className":2740},[],[2742],{"type":42,"value":399},{"type":42,"value":2744}," metapackage and ",{"type":37,"tag":83,"props":2746,"children":2748},{"className":2747},[],[2749],{"type":42,"value":379},{"type":42,"value":2751}," (and are bundled with ",{"type":37,"tag":83,"props":2753,"children":2755},{"className":2754},[],[2756],{"type":42,"value":411},{"type":42,"value":2758}," 3.7+); for other setups, reference ",{"type":37,"tag":83,"props":2760,"children":2762},{"className":2761},[],[2763],{"type":42,"value":2728},{"type":42,"value":2765}," explicitly. Most rules have an automated code fix (light bulb) in Visual Studio. When fixing one by hand, apply the idiomatic change below rather than suppressing the rule.",{"type":37,"tag":45,"props":2767,"children":2768},{},[2769,2771,2779],{"type":42,"value":2770},"When asked to \"fix MSTESTxxxx\", look it up in the table of common diagnostics below, apply the fix, and rebuild to confirm the diagnostic is gone. The table is not exhaustive — for any rule it does not list, consult the full reference and apply the documented guidance: ",{"type":37,"tag":2772,"props":2773,"children":2777},"a",{"href":2774,"rel":2775},"https:\u002F\u002Flearn.microsoft.com\u002Fdotnet\u002Fcore\u002Ftesting\u002Fmstest-analyzers\u002Foverview",[2776],"nofollow",[2778],{"type":42,"value":2774},{"type":42,"value":2780},".",{"type":37,"tag":1180,"props":2782,"children":2784},{"id":2783},"common-diagnostics-and-their-fixes",[2785],{"type":42,"value":2786},"Common diagnostics and their fixes",{"type":37,"tag":224,"props":2788,"children":2789},{},[2790,2811],{"type":37,"tag":228,"props":2791,"children":2792},{},[2793],{"type":37,"tag":232,"props":2794,"children":2795},{},[2796,2801,2806],{"type":37,"tag":236,"props":2797,"children":2798},{},[2799],{"type":42,"value":2800},"Rule",{"type":37,"tag":236,"props":2802,"children":2803},{},[2804],{"type":42,"value":2805},"Problem",{"type":37,"tag":236,"props":2807,"children":2808},{},[2809],{"type":42,"value":2810},"Fix",{"type":37,"tag":252,"props":2812,"children":2813},{},[2814,2851,2890,2920,2943,2961,3002,3032,3077,3106,3150,3174,3204,3229,3254,3285,3310],{"type":37,"tag":232,"props":2815,"children":2816},{},[2817,2822,2832],{"type":37,"tag":259,"props":2818,"children":2819},{},[2820],{"type":42,"value":2821},"MSTEST0006",{"type":37,"tag":259,"props":2823,"children":2824},{},[2825,2830],{"type":37,"tag":83,"props":2826,"children":2828},{"className":2827},[],[2829],{"type":42,"value":1244},{"type":42,"value":2831}," used",{"type":37,"tag":259,"props":2833,"children":2834},{},[2835,2837,2842,2844,2849],{"type":42,"value":2836},"Replace with ",{"type":37,"tag":83,"props":2838,"children":2840},{"className":2839},[],[2841],{"type":42,"value":1318},{"type":42,"value":2843}," \u002F ",{"type":37,"tag":83,"props":2845,"children":2847},{"className":2846},[],[2848],{"type":42,"value":1337},{"type":42,"value":2850}," (Step 3)",{"type":37,"tag":232,"props":2852,"children":2853},{},[2854,2859,2869],{"type":37,"tag":259,"props":2855,"children":2856},{},[2857],{"type":42,"value":2858},"MSTEST0017",{"type":37,"tag":259,"props":2860,"children":2861},{},[2862,2867],{"type":37,"tag":83,"props":2863,"children":2865},{"className":2864},[],[2866],{"type":42,"value":111},{"type":42,"value":2868}," args swapped",{"type":37,"tag":259,"props":2870,"children":2871},{},[2872,2874,2880,2882,2888],{"type":42,"value":2873},"Put ",{"type":37,"tag":83,"props":2875,"children":2877},{"className":2876},[],[2878],{"type":42,"value":2879},"expected",{"type":42,"value":2881}," first, ",{"type":37,"tag":83,"props":2883,"children":2885},{"className":2884},[],[2886],{"type":42,"value":2887},"actual",{"type":42,"value":2889}," second",{"type":37,"tag":232,"props":2891,"children":2892},{},[2893,2898,2910],{"type":37,"tag":259,"props":2894,"children":2895},{},[2896],{"type":42,"value":2897},"MSTEST0023",{"type":37,"tag":259,"props":2899,"children":2900},{},[2901,2903,2909],{"type":42,"value":2902},"Negated boolean assertion (",{"type":37,"tag":83,"props":2904,"children":2906},{"className":2905},[],[2907],{"type":42,"value":2908},"Assert.IsTrue(!x)",{"type":42,"value":169},{"type":37,"tag":259,"props":2911,"children":2912},{},[2913,2914],{"type":42,"value":728},{"type":37,"tag":83,"props":2915,"children":2917},{"className":2916},[],[2918],{"type":42,"value":2919},"Assert.IsFalse(x)",{"type":37,"tag":232,"props":2921,"children":2922},{},[2923,2928,2933],{"type":37,"tag":259,"props":2924,"children":2925},{},[2926],{"type":42,"value":2927},"MSTEST0025",{"type":37,"tag":259,"props":2929,"children":2930},{},[2931],{"type":42,"value":2932},"Always-false condition asserted",{"type":37,"tag":259,"props":2934,"children":2935},{},[2936,2937],{"type":42,"value":728},{"type":37,"tag":83,"props":2938,"children":2940},{"className":2939},[],[2941],{"type":42,"value":2942},"Assert.Fail(\"reason\")",{"type":37,"tag":232,"props":2944,"children":2945},{},[2946,2951,2956],{"type":37,"tag":259,"props":2947,"children":2948},{},[2949],{"type":42,"value":2950},"MSTEST0032",{"type":37,"tag":259,"props":2952,"children":2953},{},[2954],{"type":42,"value":2955},"Always-true assert condition",{"type":37,"tag":259,"props":2957,"children":2958},{},[2959],{"type":42,"value":2960},"Remove or correct the assertion",{"type":37,"tag":232,"props":2962,"children":2963},{},[2964,2969,2981],{"type":37,"tag":259,"props":2965,"children":2966},{},[2967],{"type":42,"value":2968},"MSTEST0037",{"type":37,"tag":259,"props":2970,"children":2971},{},[2972,2974,2980],{"type":42,"value":2973},"Sub-optimal assert (",{"type":37,"tag":83,"props":2975,"children":2977},{"className":2976},[],[2978],{"type":42,"value":2979},"IsTrue(x == null)",{"type":42,"value":169},{"type":37,"tag":259,"props":2982,"children":2983},{},[2984,2986,2992,2994,3000],{"type":42,"value":2985},"Use the specific assert (",{"type":37,"tag":83,"props":2987,"children":2989},{"className":2988},[],[2990],{"type":42,"value":2991},"Assert.IsNull",{"type":42,"value":2993},", ",{"type":37,"tag":83,"props":2995,"children":2997},{"className":2996},[],[2998],{"type":42,"value":2999},"HasCount",{"type":42,"value":3001},", etc.) (Step 3)",{"type":37,"tag":232,"props":3003,"children":3004},{},[3005,3010,3021],{"type":37,"tag":259,"props":3006,"children":3007},{},[3008],{"type":42,"value":3009},"MSTEST0038",{"type":37,"tag":259,"props":3011,"children":3012},{},[3013,3019],{"type":37,"tag":83,"props":3014,"children":3016},{"className":3015},[],[3017],{"type":42,"value":3018},"Assert.AreSame",{"type":42,"value":3020}," on value types",{"type":37,"tag":259,"props":3022,"children":3023},{},[3024,3025,3030],{"type":42,"value":728},{"type":37,"tag":83,"props":3026,"children":3028},{"className":3027},[],[3029],{"type":42,"value":111},{"type":42,"value":3031}," (value types box to distinct references)",{"type":37,"tag":232,"props":3033,"children":3034},{},[3035,3040,3051],{"type":37,"tag":259,"props":3036,"children":3037},{},[3038],{"type":42,"value":3039},"MSTEST0039",{"type":37,"tag":259,"props":3041,"children":3042},{},[3043,3045],{"type":42,"value":3044},"Legacy ",{"type":37,"tag":83,"props":3046,"children":3048},{"className":3047},[],[3049],{"type":42,"value":3050},"Assert.ThrowsException",{"type":37,"tag":259,"props":3052,"children":3053},{},[3054,3055,3060,3061,3067,3069,3075],{"type":42,"value":728},{"type":37,"tag":83,"props":3056,"children":3058},{"className":3057},[],[3059],{"type":42,"value":1236},{"type":42,"value":2843},{"type":37,"tag":83,"props":3062,"children":3064},{"className":3063},[],[3065],{"type":42,"value":3066},"Assert.ThrowsExactly",{"type":42,"value":3068}," (+ ",{"type":37,"tag":83,"props":3070,"children":3072},{"className":3071},[],[3073],{"type":42,"value":3074},"Async",{"type":42,"value":3076}," variants)",{"type":37,"tag":232,"props":3078,"children":3079},{},[3080,3085,3095],{"type":37,"tag":259,"props":3081,"children":3082},{},[3083],{"type":42,"value":3084},"MSTEST0044",{"type":37,"tag":259,"props":3086,"children":3087},{},[3088,3094],{"type":37,"tag":83,"props":3089,"children":3091},{"className":3090},[],[3092],{"type":42,"value":3093},"[DataTestMethod]",{"type":42,"value":2831},{"type":37,"tag":259,"props":3096,"children":3097},{},[3098,3099,3104],{"type":42,"value":2836},{"type":37,"tag":83,"props":3100,"children":3102},{"className":3101},[],[3103],{"type":42,"value":742},{"type":42,"value":3105}," (it now supports data rows)",{"type":37,"tag":232,"props":3107,"children":3108},{},[3109,3114,3123],{"type":37,"tag":259,"props":3110,"children":3111},{},[3112],{"type":42,"value":3113},"MSTEST0046",{"type":37,"tag":259,"props":3115,"children":3116},{},[3117,3122],{"type":37,"tag":83,"props":3118,"children":3120},{"className":3119},[],[3121],{"type":42,"value":1168},{"type":42,"value":2831},{"type":37,"tag":259,"props":3124,"children":3125},{},[3126,3128,3133,3135,3141,3142,3148],{"type":42,"value":3127},"Use the equivalent ",{"type":37,"tag":83,"props":3129,"children":3131},{"className":3130},[],[3132],{"type":42,"value":1160},{"type":42,"value":3134}," method (",{"type":37,"tag":83,"props":3136,"children":3138},{"className":3137},[],[3139],{"type":42,"value":3140},"Assert.Contains",{"type":42,"value":2993},{"type":37,"tag":83,"props":3143,"children":3145},{"className":3144},[],[3146],{"type":42,"value":3147},"StartsWith",{"type":42,"value":3149},", ...)",{"type":37,"tag":232,"props":3151,"children":3152},{},[3153,3158,3169],{"type":37,"tag":259,"props":3154,"children":3155},{},[3156],{"type":42,"value":3157},"MSTEST0052",{"type":37,"tag":259,"props":3159,"children":3160},{},[3161,3163],{"type":42,"value":3162},"Explicit ",{"type":37,"tag":83,"props":3164,"children":3166},{"className":3165},[],[3167],{"type":42,"value":3168},"DynamicDataSourceType",{"type":37,"tag":259,"props":3170,"children":3171},{},[3172],{"type":42,"value":3173},"Drop it — the source type is inferred",{"type":37,"tag":232,"props":3175,"children":3176},{},[3177,3182,3199],{"type":37,"tag":259,"props":3178,"children":3179},{},[3180],{"type":42,"value":3181},"MSTEST0042 \u002F MSTEST0060",{"type":37,"tag":259,"props":3183,"children":3184},{},[3185,3187,3193,3194],{"type":42,"value":3186},"Duplicate ",{"type":37,"tag":83,"props":3188,"children":3190},{"className":3189},[],[3191],{"type":42,"value":3192},"[DataRow]",{"type":42,"value":2843},{"type":37,"tag":83,"props":3195,"children":3197},{"className":3196},[],[3198],{"type":42,"value":742},{"type":37,"tag":259,"props":3200,"children":3201},{},[3202],{"type":42,"value":3203},"Remove the duplicate attribute",{"type":37,"tag":232,"props":3205,"children":3206},{},[3207,3212,3224],{"type":37,"tag":259,"props":3208,"children":3209},{},[3210],{"type":42,"value":3211},"MSTEST0024",{"type":37,"tag":259,"props":3213,"children":3214},{},[3215,3217,3222],{"type":42,"value":3216},"Static ",{"type":37,"tag":83,"props":3218,"children":3220},{"className":3219},[],[3221],{"type":42,"value":2144},{"type":42,"value":3223}," field",{"type":37,"tag":259,"props":3225,"children":3226},{},[3227],{"type":42,"value":3228},"Make it an instance member (Step 5)",{"type":37,"tag":232,"props":3230,"children":3231},{},[3232,3237,3242],{"type":37,"tag":259,"props":3233,"children":3234},{},[3235],{"type":42,"value":3236},"MSTEST0045 \u002F MSTEST0049 \u002F MSTEST0054",{"type":37,"tag":259,"props":3238,"children":3239},{},[3240],{"type":42,"value":3241},"Timeout\u002Ftoken not cooperative",{"type":37,"tag":259,"props":3243,"children":3244},{},[3245,3247,3252],{"type":42,"value":3246},"Flow ",{"type":37,"tag":83,"props":3248,"children":3250},{"className":3249},[],[3251],{"type":42,"value":2479},{"type":42,"value":3253}," into the awaited call (Step 6)",{"type":37,"tag":232,"props":3255,"children":3256},{},[3257,3262,3267],{"type":37,"tag":259,"props":3258,"children":3259},{},[3260],{"type":42,"value":3261},"MSTEST0036",{"type":37,"tag":259,"props":3263,"children":3264},{},[3265],{"type":42,"value":3266},"Member shadows a base test member",{"type":37,"tag":259,"props":3268,"children":3269},{},[3270,3272,3278,3279],{"type":42,"value":3271},"Rename or use ",{"type":37,"tag":83,"props":3273,"children":3275},{"className":3274},[],[3276],{"type":42,"value":3277},"override",{"type":42,"value":1238},{"type":37,"tag":83,"props":3280,"children":3282},{"className":3281},[],[3283],{"type":42,"value":3284},"new",{"type":37,"tag":232,"props":3286,"children":3287},{},[3288,3293,3298],{"type":37,"tag":259,"props":3289,"children":3290},{},[3291],{"type":42,"value":3292},"MSTEST0061",{"type":37,"tag":259,"props":3294,"children":3295},{},[3296],{"type":42,"value":3297},"Runtime OS check inside a test",{"type":37,"tag":259,"props":3299,"children":3300},{},[3301,3302,3308],{"type":42,"value":728},{"type":37,"tag":83,"props":3303,"children":3305},{"className":3304},[],[3306],{"type":42,"value":3307},"[OSCondition(...)]",{"type":42,"value":3309}," (Step 7)",{"type":37,"tag":232,"props":3311,"children":3312},{},[3313,3318,3330],{"type":37,"tag":259,"props":3314,"children":3315},{},[3316],{"type":42,"value":3317},"MSTEST0002 \u002F MSTEST0003 \u002F MSTEST0005 \u002F MSTEST0007–0014",{"type":37,"tag":259,"props":3319,"children":3320},{},[3321,3323,3328],{"type":42,"value":3322},"Invalid test class \u002F method \u002F fixture \u002F ",{"type":37,"tag":83,"props":3324,"children":3326},{"className":3325},[],[3327],{"type":42,"value":2144},{"type":42,"value":3329}," \u002F data-source layout",{"type":37,"tag":259,"props":3331,"children":3332},{},[3333,3335,3341],{"type":42,"value":3334},"Correct the signature named by the rule (e.g. make it public, fix the return type and parameters, add ",{"type":37,"tag":83,"props":3336,"children":3338},{"className":3337},[],[3339],{"type":42,"value":3340},"static",{"type":42,"value":3342}," where required)",{"type":37,"tag":1180,"props":3344,"children":3346},{"id":3345},"tuning-which-rules-are-enforced",[3347],{"type":42,"value":3348},"Tuning which rules are enforced",{"type":37,"tag":45,"props":3350,"children":3351},{},[3352,3354,3360],{"type":42,"value":3353},"Use the ",{"type":37,"tag":83,"props":3355,"children":3357},{"className":3356},[],[3358],{"type":42,"value":3359},"MSTestAnalysisMode",{"type":42,"value":3361}," MSBuild property (MSTest 3.8+) to control the rule set globally:",{"type":37,"tag":428,"props":3363,"children":3365},{"className":430,"code":3364,"language":432,"meta":433,"style":433},"\u003CPropertyGroup>\n  \u003C!-- None | Default | Recommended | All -->\n  \u003CMSTestAnalysisMode>Recommended\u003C\u002FMSTestAnalysisMode>\n\u003C\u002FPropertyGroup>\n",[3366],{"type":37,"tag":83,"props":3367,"children":3368},{"__ignoreMap":433},[3369,3377,3385,3393],{"type":37,"tag":439,"props":3370,"children":3371},{"class":441,"line":442},[3372],{"type":37,"tag":439,"props":3373,"children":3374},{},[3375],{"type":42,"value":3376},"\u003CPropertyGroup>\n",{"type":37,"tag":439,"props":3378,"children":3379},{"class":441,"line":451},[3380],{"type":37,"tag":439,"props":3381,"children":3382},{},[3383],{"type":42,"value":3384},"  \u003C!-- None | Default | Recommended | All -->\n",{"type":37,"tag":439,"props":3386,"children":3387},{"class":441,"line":460},[3388],{"type":37,"tag":439,"props":3389,"children":3390},{},[3391],{"type":42,"value":3392},"  \u003CMSTestAnalysisMode>Recommended\u003C\u002FMSTestAnalysisMode>\n",{"type":37,"tag":439,"props":3394,"children":3395},{"class":441,"line":469},[3396],{"type":37,"tag":439,"props":3397,"children":3398},{},[3399],{"type":42,"value":3400},"\u003C\u002FPropertyGroup>\n",{"type":37,"tag":58,"props":3402,"children":3403},{},[3404,3415,3428],{"type":37,"tag":62,"props":3405,"children":3406},{},[3407,3413],{"type":37,"tag":83,"props":3408,"children":3410},{"className":3409},[],[3411],{"type":42,"value":3412},"Recommended",{"type":42,"value":3414}," escalates info-level rules to warnings and is the mode most projects should adopt.",{"type":37,"tag":62,"props":3416,"children":3417},{},[3418,3420,3426],{"type":42,"value":3419},"A handful of rules are completely opt-in (e.g. MSTEST0015, MSTEST0019–0022); enable them per project via ",{"type":37,"tag":83,"props":3421,"children":3423},{"className":3422},[],[3424],{"type":42,"value":3425},".editorconfig",{"type":42,"value":3427}," when you want their convention enforced.",{"type":37,"tag":62,"props":3429,"children":3430},{},[3431],{"type":42,"value":3432},"Prefer fixing the underlying code over suppressing a diagnostic. Suppress only with a documented justification.",{"type":37,"tag":3434,"props":3435,"children":3436},"style",{},[3437],{"type":42,"value":3438},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"items":3440,"total":3546},[3441,3458,3473,3491,3503,3522,3532],{"slug":3442,"name":3442,"fn":3443,"description":3444,"org":3445,"tags":3446,"stars":19,"repoUrl":20,"updatedAt":3457},"analyzing-dotnet-performance","analyze .NET code for performance anti-patterns","Scans .NET code for ~50 performance anti-patterns across async, memory, strings, collections, LINQ, regex, serialization, and I\u002FO with tiered severity classification. Use when analyzing .NET code for optimization opportunities, reviewing hot paths, or auditing allocation-heavy patterns.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3447,3448,3451,3454],{"name":13,"slug":14,"type":15},{"name":3449,"slug":3450,"type":15},"Code Analysis","code-analysis",{"name":3452,"slug":3453,"type":15},"Debugging","debugging",{"name":3455,"slug":3456,"type":15},"Performance","performance","2026-07-12T08:23:25.400375",{"slug":3459,"name":3459,"fn":3460,"description":3461,"org":3462,"tags":3463,"stars":19,"repoUrl":20,"updatedAt":3472},"android-tombstone-symbolication","symbolicate .NET runtime frames in Android tombstones","Symbolicate the .NET runtime frames in an Android tombstone file. Extracts BuildIds and PC offsets from the native backtrace, downloads debug symbols from the Microsoft symbol server, and runs llvm-symbolizer to produce function names with source file and line numbers. USE FOR triaging a .NET MAUI or Mono Android app crash from a tombstone, resolving native backtrace frames in libmonosgen-2.0.so or libcoreclr.so to .NET runtime source code, or investigating SIGABRT, SIGSEGV, or other native signals originating from the .NET runtime on Android. DO NOT USE FOR pure Java\u002FKotlin crashes, managed .NET exceptions that are already captured in logcat, or iOS crash logs. INVOKES Symbolicate-Tombstone.ps1 script, llvm-symbolizer, Microsoft symbol server.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3464,3465,3468,3469],{"name":13,"slug":14,"type":15},{"name":3466,"slug":3467,"type":15},"Android","android",{"name":3452,"slug":3453,"type":15},{"name":3470,"slug":3471,"type":15},"Microsoft","microsoft","2026-07-12T08:23:21.595572",{"slug":3474,"name":3474,"fn":3475,"description":3476,"org":3477,"tags":3478,"stars":19,"repoUrl":20,"updatedAt":3490},"apple-crash-symbolication","symbolicate .NET runtime frames in crash logs","Symbolicate .NET runtime frames in Apple platform .ips crash logs (iOS, tvOS, Mac Catalyst, macOS). Extracts UUIDs and addresses from the native backtrace, locates dSYM debug symbols, and runs atos to produce function names with source file and line numbers. Automatically downloads .dwarf symbols from the Microsoft symbol server using Mach-O UUIDs. USE FOR triaging a .NET MAUI or Mono app crash from an .ips file on any Apple platform, resolving native backtrace frames in libcoreclr or libmonosgen-2.0 to .NET runtime source code, retrieving .ips crash logs from a connected iOS device or iPhone, or investigating EXC_CRASH, EXC_BAD_ACCESS, SIGABRT, or SIGSEGV originating from the .NET runtime. DO NOT USE FOR pure Swift\u002FObjective-C crashes with no .NET components, or Android tombstone files. INVOKES Symbolicate-Crash.ps1 script, atos, dwarfdump, idevicecrashreport.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3479,3480,3481,3484,3487],{"name":13,"slug":14,"type":15},{"name":3452,"slug":3453,"type":15},{"name":3482,"slug":3483,"type":15},"iOS","ios",{"name":3485,"slug":3486,"type":15},"macOS","macos",{"name":3488,"slug":3489,"type":15},"Observability","observability","2026-07-12T08:23:20.369986",{"slug":3492,"name":3492,"fn":3493,"description":3494,"org":3495,"tags":3496,"stars":19,"repoUrl":20,"updatedAt":3502},"assertion-quality","evaluate assertion quality in test suites","Analyzes the variety and depth of assertions across test suites in any language. Use when the user asks to evaluate assertion quality, find shallow tests, identify assertion-free tests (no assertions or only trivial ones like Assert.IsNotNull \u002F toBeTruthy()), flag self-referential or tautological assertions, measure assertion diversity, or audit whether tests verify different facets of behavior. Polyglot: .NET, Python, TS\u002FJS, Java, Go, Ruby, Rust, Swift, Kotlin, PowerShell, C++. DO NOT USE FOR: writing new tests (use code-testing-agent \u002F writing-mstest-tests), mutation reasoning about whether tests would catch a bug (use test-gap-analysis), or a general severity-ranked anti-pattern audit (use test-anti-patterns), fixing or rewriting assertions, or writing, fixing, or modernizing MSTest tests, assertions, or attributes (use writing-mstest-tests).",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3497,3498,3501],{"name":3449,"slug":3450,"type":15},{"name":3499,"slug":3500,"type":15},"QA","qa",{"name":17,"slug":18,"type":15},"2026-07-12T08:23:51.277743",{"slug":3504,"name":3504,"fn":3505,"description":3506,"org":3507,"tags":3508,"stars":19,"repoUrl":20,"updatedAt":3521},"author-component","create and review Blazor components","Create or review Blazor components (.razor files) with correct architecture. USE FOR: writing new Blazor components that do NOT involve JavaScript interop, implementing parameters and EventCallback, RenderFragment slots, component lifecycle (OnInitializedAsync, OnParametersSet), async patterns, IAsyncDisposable, CancellationToken, CSS isolation, code-behind. DO NOT USE FOR: creating new projects (use create-blazor-project), JavaScript interop or calling browser APIs from Blazor (use use-js-interop), forms and validation (use collect-user-input), prerendering issues (use support-prerendering), HTTP data fetching patterns (use fetch-and-send-data), coordinating state between unrelated components (use coordinate-components).\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3509,3510,3513,3515,3518],{"name":13,"slug":14,"type":15},{"name":3511,"slug":3512,"type":15},"Blazor","blazor",{"name":3514,"slug":783,"type":15},"C#",{"name":3516,"slug":3517,"type":15},"UI Components","ui-components",{"name":3519,"slug":3520,"type":15},"Web Development","web-development","2026-07-15T06:03:29.216359",{"slug":3523,"name":3523,"fn":3524,"description":3525,"org":3526,"tags":3527,"stars":19,"repoUrl":20,"updatedAt":3531},"binlog-failure-analysis","analyze MSBuild binary logs","Analyze MSBuild binary logs to diagnose build failures. USE FOR: build errors that are unclear from console output, diagnosing cascading failures across multi-project builds, tracing MSBuild target execution order, and generally any MSBuild build issues. Requires an existing .binlog file. DO NOT USE FOR: generating binlogs (use binlog-generation), non-MSBuild build systems.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3528,3529,3530],{"name":3449,"slug":3450,"type":15},{"name":3452,"slug":3453,"type":15},{"name":3470,"slug":3471,"type":15},"2026-07-12T08:21:34.637923",{"slug":3533,"name":3533,"fn":3534,"description":3535,"org":3536,"tags":3537,"stars":19,"repoUrl":20,"updatedAt":3545},"binlog-generation","generate MSBuild binary logs for diagnostics","Generate MSBuild binary logs (binlogs) for build diagnostics and analysis. USE FOR: adding \u002Fbl:{} to any dotnet build, test, pack, publish, or restore command to capture a full build execution trace, prerequisite for binlog-failure-analysis and build-perf-diagnostics skills, enabling post-build investigation of errors or performance. Requires MSBuild 17.8+ \u002F .NET 8 SDK+ for {} placeholder; PowerShell needs -bl:{{}}. DO NOT USE FOR: non-MSBuild build systems (npm, Maven, CMake), analyzing an existing binlog (use binlog-failure-analysis instead).",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3538,3541,3542],{"name":3539,"slug":3540,"type":15},"Build","build",{"name":3452,"slug":3453,"type":15},{"name":3543,"slug":3544,"type":15},"Engineering","engineering","2026-07-19T05:38:19.340791",96,{"items":3548,"total":3653},[3549,3561,3568,3575,3583,3589,3597,3603,3609,3619,3632,3643],{"slug":3550,"name":3550,"fn":3551,"description":3552,"org":3553,"tags":3554,"stars":3558,"repoUrl":3559,"updatedAt":3560},"multithreaded-task-migration","migrate MSBuild tasks to multithreaded mode","Guide for migrating MSBuild tasks to multithreaded mode support, including compatibility red-team review. Use this when converting tasks to thread-safe versions, implementing IMultiThreadableTask, adding TaskEnvironment support, or auditing migrations for behavioral compatibility.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3555,3556,3557],{"name":13,"slug":14,"type":15},{"name":3543,"slug":3544,"type":15},{"name":3455,"slug":3456,"type":15},5535,"https:\u002F\u002Fgithub.com\u002Fdotnet\u002Fmsbuild","2026-07-22T05:37:33.965588",{"slug":3442,"name":3442,"fn":3443,"description":3444,"org":3562,"tags":3563,"stars":19,"repoUrl":20,"updatedAt":3457},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3564,3565,3566,3567],{"name":13,"slug":14,"type":15},{"name":3449,"slug":3450,"type":15},{"name":3452,"slug":3453,"type":15},{"name":3455,"slug":3456,"type":15},{"slug":3459,"name":3459,"fn":3460,"description":3461,"org":3569,"tags":3570,"stars":19,"repoUrl":20,"updatedAt":3472},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3571,3572,3573,3574],{"name":13,"slug":14,"type":15},{"name":3466,"slug":3467,"type":15},{"name":3452,"slug":3453,"type":15},{"name":3470,"slug":3471,"type":15},{"slug":3474,"name":3474,"fn":3475,"description":3476,"org":3576,"tags":3577,"stars":19,"repoUrl":20,"updatedAt":3490},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3578,3579,3580,3581,3582],{"name":13,"slug":14,"type":15},{"name":3452,"slug":3453,"type":15},{"name":3482,"slug":3483,"type":15},{"name":3485,"slug":3486,"type":15},{"name":3488,"slug":3489,"type":15},{"slug":3492,"name":3492,"fn":3493,"description":3494,"org":3584,"tags":3585,"stars":19,"repoUrl":20,"updatedAt":3502},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3586,3587,3588],{"name":3449,"slug":3450,"type":15},{"name":3499,"slug":3500,"type":15},{"name":17,"slug":18,"type":15},{"slug":3504,"name":3504,"fn":3505,"description":3506,"org":3590,"tags":3591,"stars":19,"repoUrl":20,"updatedAt":3521},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3592,3593,3594,3595,3596],{"name":13,"slug":14,"type":15},{"name":3511,"slug":3512,"type":15},{"name":3514,"slug":783,"type":15},{"name":3516,"slug":3517,"type":15},{"name":3519,"slug":3520,"type":15},{"slug":3523,"name":3523,"fn":3524,"description":3525,"org":3598,"tags":3599,"stars":19,"repoUrl":20,"updatedAt":3531},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3600,3601,3602],{"name":3449,"slug":3450,"type":15},{"name":3452,"slug":3453,"type":15},{"name":3470,"slug":3471,"type":15},{"slug":3533,"name":3533,"fn":3534,"description":3535,"org":3604,"tags":3605,"stars":19,"repoUrl":20,"updatedAt":3545},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3606,3607,3608],{"name":3539,"slug":3540,"type":15},{"name":3452,"slug":3453,"type":15},{"name":3543,"slug":3544,"type":15},{"slug":3610,"name":3610,"fn":3611,"description":3612,"org":3613,"tags":3614,"stars":19,"repoUrl":20,"updatedAt":3618},"build-parallelism","optimize MSBuild build parallelism","Diagnose and fix under-parallelized MSBuild builds. USE WHEN a multi-project solution build is slower than expected, doesn't speed up when you add cores, pegs a single core while others idle, or you want to know why `-m` isn't helping. Note: `\u002Fmaxcpucount` default is 1 (sequential) — always pass `-m` for parallel builds. Covers finding the critical path (longest serial ProjectReference chain), graph build (`\u002Fgraph`), BuildInParallel, and solution filters (`.slnf`). DO NOT USE FOR: single-project builds, incremental issues (use incremental-build), compilation slowness inside one project (use build-perf-diagnostics), non-MSBuild build systems.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3615,3616,3617],{"name":13,"slug":14,"type":15},{"name":3543,"slug":3544,"type":15},{"name":3455,"slug":3456,"type":15},"2026-07-19T05:38:18.364937",{"slug":3620,"name":3620,"fn":3621,"description":3622,"org":3623,"tags":3624,"stars":19,"repoUrl":20,"updatedAt":3631},"build-perf-baseline","establish and optimize build performance baselines","Establish build performance baselines and apply systematic optimization techniques. USE FOR: diagnosing slow builds, establishing before\u002Fafter measurements (cold, warm, no-op scenarios), applying optimization strategies like MSBuild Server, static graph builds, artifacts output, and dependency graph trimming. Start here before diving into build-perf-diagnostics, incremental-build, or build-parallelism. DO NOT USE FOR: non-MSBuild build systems, detailed bottleneck analysis (use build-perf-diagnostics after baselining).",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3625,3626,3629,3630],{"name":3543,"slug":3544,"type":15},{"name":3627,"slug":3628,"type":15},"Monitoring","monitoring",{"name":3455,"slug":3456,"type":15},{"name":17,"slug":18,"type":15},"2026-07-12T08:21:35.865649",{"slug":3633,"name":3633,"fn":3634,"description":3635,"org":3636,"tags":3637,"stars":19,"repoUrl":20,"updatedAt":3642},"build-perf-diagnostics","diagnose MSBuild build performance bottlenecks","Diagnose MSBuild build performance bottlenecks using binary log analysis. USE FOR: identifying why builds are slow by analyzing binlog performance summaries, detecting ResolveAssemblyReference (RAR) taking >5s, Roslyn analyzers consuming >30% of Csc time, single targets dominating >50% of build time, node utilization below 80%, excessive Copy tasks, NuGet restore running every build. Covers timeline analysis, Target\u002FTask Performance Summary interpretation, and 7 common bottleneck categories. Use after build-perf-baseline has established measurements. DO NOT USE FOR: establishing initial baselines (use build-perf-baseline first), fixing incremental build issues (use incremental-build), parallelism tuning (use build-parallelism), non-MSBuild build systems.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3638,3639,3640,3641],{"name":13,"slug":14,"type":15},{"name":3452,"slug":3453,"type":15},{"name":3543,"slug":3544,"type":15},{"name":3455,"slug":3456,"type":15},"2026-07-12T08:21:40.961722",{"slug":3644,"name":3644,"fn":3645,"description":3646,"org":3647,"tags":3648,"stars":19,"repoUrl":20,"updatedAt":3652},"check-bin-obj-clash","detect MSBuild output path conflicts","Detects MSBuild projects with conflicting OutputPath or IntermediateOutputPath. USE FOR: builds failing with 'Cannot create a file when that file already exists', 'The process cannot access the file because it is being used by another process', intermittent build failures that succeed on retry, or missing\u002Foverwritten outputs in multi-project or multi-targeting builds where bin\u002Fobj (or project.assets.json) collide. Common causes: shared OutputPath, missing AppendTargetFrameworkToOutputPath, extra global properties (e.g. PublishReadyToRun), or SetTargetFramework on a ProjectReference to a single-targeting project. DO NOT USE FOR: file access errors unrelated to MSBuild (OS-level locking), single-project single-TFM builds, non-MSBuild build systems.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3649,3650,3651],{"name":3452,"slug":3453,"type":15},{"name":3543,"slug":3544,"type":15},{"name":3499,"slug":3500,"type":15},"2026-07-19T05:38:14.336279",144]