[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-dotnet-test-anti-patterns":3,"mdc-mmt3mn-key":37,"related-repo-dotnet-test-anti-patterns":3176,"related-org-dotnet-test-anti-patterns":3281},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":11,"stars":25,"repoUrl":26,"updatedAt":27,"license":28,"forks":29,"topics":30,"repo":32,"sourceUrl":35,"mdContent":36},"test-anti-patterns","audit test suites for anti-patterns","Audits an existing test file or suite in any language for anti-patterns and quality issues — produces a severity-ranked report (Critical\u002FWarning\u002FInfo). INVOKE whenever asked to audit or review tests, find what's wrong with a suite, judge whether tests are any good, or check for: tests that pass but verify nothing, missing assertions, swallowed exceptions, self-comparing \u002F tautological assertions, coverage-touching tests, broad exceptions, flaky or order-dependent tests (Thread.Sleep, DateTime.Now, shared state), duplicated tests, or magic values — in .NET, Python\u002Fpytest, TS\u002FJest, Java, Go, Ruby or C++. DO NOT USE FOR: writing new tests (use code-testing-agent, or writing-mstest-tests for MSTest); running tests (use run-tests); migration; assertion-diversity metrics (use assertion-quality); coverage\u002FCRAP metrics (use coverage-analysis); the testsmells.org academic catalog (use test-smell-detection); fixing or modernizing MSTest tests, assertions, attributes, or lifecycle (use writing-mstest-tests).\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,19,22],{"name":13,"slug":14,"type":15},".NET","net","tag",{"name":17,"slug":18,"type":15},"Code Analysis","code-analysis",{"name":20,"slug":21,"type":15},"Testing","testing",{"name":23,"slug":24,"type":15},"Debugging","debugging",4576,"https:\u002F\u002Fgithub.com\u002Fdotnet\u002Fskills","2026-08-01T05:42:24.17497","MIT",332,[31],"agent-skills",{"repoUrl":26,"stars":25,"forks":29,"topics":33,"description":34},[31],"Repository for skills to assist AI coding agents with .NET and C#","https:\u002F\u002Fgithub.com\u002Fdotnet\u002Fskills\u002Ftree\u002FHEAD\u002Fplugins\u002Fdotnet-test\u002Fskills\u002Ftest-anti-patterns","---\nname: test-anti-patterns\ndescription: >\n  Audits an existing test file or suite in any language for anti-patterns\n  and quality issues — produces a severity-ranked report\n  (Critical\u002FWarning\u002FInfo). INVOKE whenever asked to audit or review tests,\n  find what's wrong with a suite, judge whether tests are any good, or\n  check for: tests that pass but verify nothing, missing assertions,\n  swallowed exceptions, self-comparing \u002F tautological assertions,\n  coverage-touching tests, broad exceptions, flaky or order-dependent tests\n  (Thread.Sleep, DateTime.Now, shared state), duplicated tests, or magic\n  values — in .NET, Python\u002Fpytest, TS\u002FJest, Java, Go, Ruby or C++. DO NOT\n  USE FOR: writing new tests (use code-testing-agent, or writing-mstest-tests\n  for MSTest); running tests (use\n  run-tests); migration; assertion-diversity metrics (use assertion-quality);\n  coverage\u002FCRAP metrics (use coverage-analysis); the testsmells.org academic\n  catalog (use test-smell-detection); fixing or modernizing MSTest tests,\n  assertions, attributes, or lifecycle (use writing-mstest-tests).\nlicense: MIT\n---\n\n# Test Anti-Pattern Detection\n\nQuick, pragmatic analysis of test code in any supported language for anti-patterns and quality issues that undermine test reliability, maintainability, and diagnostic value.\n\n> **Language-specific guidance**: Call the `test-analysis-extensions` skill to discover available extension files, then read the file matching the target codebase (e.g., `extensions\u002Fdotnet.md`, `extensions\u002Fpython.md`, `extensions\u002Ftypescript.md`, `extensions\u002Fgo.md`). The extension file tells you which sleep \u002F time \u002F random \u002F skip \u002F setup-teardown \u002F mystery-guest APIs to look for in that language.\n\n## When to Use\n\n- User asks to review test quality or find test smells\n- User wants to know why tests are flaky or unreliable\n- User asks \"are my tests good?\" or \"what's wrong with my tests?\"\n- User requests a test audit or test code review\n- User wants to improve existing test code\n\n## When Not to Use\n\n- User wants to write new tests from scratch (use `code-testing-agent` for any language, or `writing-mstest-tests` for MSTest specifically)\n- User wants direct implementation fixes rather than a diagnostic review (use the relevant write\u002Fedit skill)\n- User asks to fix swapped `Assert.AreEqual` argument order in MSTest (use `writing-mstest-tests`)\n- User asks to convert MSTest `DynamicData` from `IEnumerable\u003Cobject[]>` to `ValueTuple` (use `writing-mstest-tests`)\n- User wants to run or execute tests (use `run-tests` for .NET)\n- User wants to migrate between test frameworks or versions (use migration skills)\n- User wants to measure code coverage (out of scope)\n- User wants a deep formal test smell audit with academic taxonomy and extended catalog (use `test-smell-detection`)\n\n## Inputs\n\n| Input | Required | Description |\n|-------|----------|-------------|\n| Test code | Yes | One or more test files or classes to analyze |\n| Production code | No | The code under test, for context on what tests should verify |\n| Specific concern | No | A focused area like \"flakiness\" or \"naming\" to narrow the review |\n\n## Workflow\n\n### Step 1: Detect language and load extension\n\nIdentify the target codebase's language and test framework. Call the `test-analysis-extensions` skill and read the matching extension file. The extension file documents framework-specific anti-pattern markers — what counts as a sleep\u002Fwait, a test marker, a skip, a setup\u002Fteardown, a shared-state hot spot, and an integration boundary — so this skill stays language-neutral.\n\n### Step 2: Gather the test code\n\nRead the test files the user wants reviewed. If the user points to a directory or project, scan for all test files using the discovery markers in the loaded language extension file (e.g., `[TestClass]`\u002F`[Fact]`\u002F`[Test]` for .NET, `test_*.py` \u002F `def test_*` for pytest, `*.test.ts` \u002F `it()` for Jest, `*Test.java` \u002F `@Test` for JUnit, `*_test.go` \u002F `func TestXxx` for Go, `*_spec.rb` for RSpec, `#[test]` for Rust, `*.Tests.ps1` \u002F `Describe` for Pester, `TEST(...)` for GoogleTest, `TEST_CASE(...)` for Catch2\u002Fdoctest).\n\nIf production code is available, read it too -- this is critical for detecting tests that are coupled to implementation details rather than behavior.\n\n### Step 3: Scan for anti-patterns\n\nCheck each test file against the anti-pattern catalog below. Report findings grouped by severity. The examples are .NET-centric but the patterns generalize — use the loaded language extension file to map each pattern to the framework you are auditing.\n\n#### Critical -- Tests that give false confidence\n\n| Anti-Pattern | What to Look For |\n|---|---|\n| **No assertions** | Test methods that execute code but never assert anything. A passing test without assertions proves nothing. In .NET look for missing `Assert.*`; in pytest a function with no `assert` and no `pytest.raises`; in Jest no `expect(...)`; in JUnit no `assert*`\u002F`assertThat`; in Go a test that never calls `t.Error*`, `t.Fatal*`, or testify; in RSpec a block with no `expect`; in Pester no `Should`. Mock-call verifications (`verify(mock)`, `expect(mock).toHaveBeenCalled`, `Should -Invoke`) are real assertions. |\n| **Missing await on async assertions (JS\u002FTS, .NET, Python, Kotlin, Swift)** | `expect(promise).resolves.toBe(x)` without `await`\u002F`return`, `pytest-asyncio` test with un-awaited coroutine, `async Task` xUnit test calling `Assert.ThrowsAsync` without `await`, Kotest suspending test without `runTest`, Swift Testing async test without `await`. These tests silently pass even when the underlying assertion would have failed. |\n| **Coverage touching** | Test class that methodically calls every public member on a type — often in alphabetical or declaration order — without asserting meaningful outcomes. Each test typically does `var result = sut.MethodName(...)` (or `result = sut.method_name(...)`, `sut.methodName()`, `sut.MethodName(t)`) with no assertion, or only a trivial null\u002FNone\u002Fnil check. The intent is to inflate code-coverage metrics rather than verify behavior. Distinct from a single assertion-free test: the pattern is *systematic* coverage of the surface area with no real verification. |\n| **Self-referential assertion** | Asserts that the output of an operation equals its input when the operation is expected to be an identity or no-op, e.g. `Assert.AreEqual(input, Parse(input.ToString()))`, `assert input == parse(str(input))`, `expect(parse(input.toString())).toBe(input)`, `assert.Equal(t, input, parse(input))`. Also flags `Assert.AreEqual(dto.Name, dto.Name)` \u002F `assert dto.name == dto.name` \u002F `expect(dto.name).toBe(dto.name)` (asserting a field against itself). The test is tautological — it can only fail if the round-trip is broken, but never verifies that a *transformation* actually happened. |\n| **Swallowed exceptions** | `try { ... } catch { }`, `catch (Exception)` without rethrowing or asserting (.NET); bare `except:` or `except Exception:` with `pass` (Python); `try { ... } catch (e) {}` (JS\u002FTS\u002FJava); `defer recover()` without re-panic and no assertion (Go); `rescue StandardError` with no assertion (Ruby); `Result::unwrap_or(...)` swallowing errors in a test (Rust); empty `catch` block (Kotlin\u002FSwift). |\n| **Assert in catch block only** | `try { Act(); } catch (Exception ex) { Assert.Fail(ex.Message); }` (and equivalents in other languages) -- use `Assert.ThrowsException` \u002F `pytest.raises` \u002F `expect(fn).toThrow` \u002F `assertThrows` \u002F `assert.Error(t, err)` \u002F `#[should_panic]` \u002F `Should -Throw` \u002F `EXPECT_THROW` instead. The test passes when no exception is thrown even if the result is wrong. |\n| **Always-true assertions** | `Assert.IsTrue(true)`, `Assert.AreEqual(x, x)`, `assert True`, `expect(true).toBe(true)`, `assert.True(t, true)`, `assert!(true)`, or conditions that can never fail. |\n| **Commented-out assertions** | Assertions that were disabled but the test still runs, giving the illusion of coverage. |\n\n#### High -- Tests likely to cause pain\n\n| Anti-Pattern | What to Look For |\n|---|---|\n| **Flakiness indicators** | Wall-clock sleeps\u002Fwaits used for synchronization: `Thread.Sleep` \u002F `Task.Delay` (.NET), `time.sleep` (Python), `setTimeout` \u002F `await new Promise(r => setTimeout(...))` (JS\u002FTS), `Thread.sleep` (Java\u002FKotlin), `time.Sleep` (Go), `sleep` (Ruby\u002FBash), `std::thread::sleep` (Rust), `Start-Sleep` (Pester), `std::this_thread::sleep_for` (C++). Wall-clock reads without abstraction: `DateTime.Now`\u002F`UtcNow`, `datetime.now()`\u002F`datetime.utcnow()`, `Date.now()` \u002F `new Date()`, `System.currentTimeMillis()`, `time.Now()`, `Time.now`, `Instant::now()`, `Date()`\u002F`Date.now`, `Get-Date`, `std::chrono::system_clock::now`. Unseeded randomness: `new Random()`, `random.random()`\u002F`random.randint()`, `Math.random()`, `new Random()` (Java\u002FKotlin), `rand.Int()` without seed, `rand` (Ruby), `rand::random()` (Rust). Environment-dependent paths (hard-coded `C:\\...`, `\u002Ftmp\u002F...`, network hosts). |\n| **Test ordering dependency** | Static\u002Fglobal mutable state modified across tests; setup that doesn't fully reset state (`[TestInitialize]`, `setUp`, `beforeEach`, `before(:each)`, `BeforeEach`, `t.Cleanup`); tests that fail when run individually but pass in suite (or vice versa). Examples per language: `static` fields (.NET\u002FJava), module-level globals (Python), top-level `let`\u002F`const` in test file (JS\u002FTS), `var` package globals (Go), class variables (Ruby), `static mut`\u002F`lazy_static!`\u002F`OnceCell` (Rust), `$script:` variables (PowerShell). |\n| **Over-mocking** | More mock setup lines than actual test logic. Verifying exact call sequences on mocks rather than outcomes. Mocking types the test owns. Per language: Moq\u002FNSubstitute\u002FFakeItEasy (.NET), `unittest.mock` \u002F `pytest-mock` (Python), Jest auto-mocks \u002F Sinon (JS\u002FTS), Mockito\u002FPowerMock (Java), gomock\u002Ftestify mock (Go), RSpec mocks\u002Fmocha (Ruby), `mockall` (Rust), MockK (Kotlin), `Mock` cmdlet (Pester), gmock (C++). For a deep mock audit in .NET, use `exp-mock-usage-analysis`. |\n| **Implementation coupling** | Testing private methods via reflection (`MethodInfo.Invoke`, `getattr` in Python, `(thing as any)` in TS, `Field.setAccessible(true)` in Java, `Object#send` in Ruby, internal `pub(crate)` access in Rust). Asserting on internal state instead of observable behavior. Verifying exact method call counts on collaborators instead of business outcomes. |\n| **Broad exception assertions** | `Assert.ThrowsException\u003CException>(...)` (.NET) \u002F `pytest.raises(Exception)` \u002F `expect(fn).toThrow(Error)` without a message matcher \u002F `assertThrows(Exception.class, ...)` (Java) \u002F `assert.Error(t, err)` without checking the kind \u002F `expect { ... }.to raise_error` without class (RSpec) \u002F `#[should_panic]` without `expected = \"...\"` \u002F `Should -Throw` without `-ExpectedMessage` \u002F `EXPECT_ANY_THROW` instead of `EXPECT_THROW(stmt, SpecificType)`. |\n\n#### Medium -- Maintainability and clarity issues\n\n| Anti-Pattern | What to Look For |\n|---|---|\n| **Poor naming** | Test names like `Test1`, `TestMethod`, `test`, names that don't describe the scenario or expected outcome. Good naming differs by language convention — see the loaded language extension file (e.g., `Add_NegativeNumber_ThrowsArgumentException` for .NET, `test_add_negative_number_raises_value_error` for pytest, `addNegativeNumber_throwsArgumentException` for Java, `'adds negative number throws'` for Jest descriptions, `TestAdd_NegativeNumber_ReturnsError` for Go). |\n| **Magic values** | Unexplained numbers or strings in arrange\u002Fassert: `Assert.AreEqual(42, result)` \u002F `assert result == 42` \u002F `expect(result).toBe(42)` -- what does 42 mean? |\n| **Duplicate tests** | Three or more test methods with near-identical bodies that differ only in a single input value. Should be parametrized: `[DataRow]`\u002F`[Theory]`\u002F`[TestCase]` (.NET), `@pytest.mark.parametrize` (pytest), `test.each` \u002F `it.each` (Jest\u002FVitest), `@ParameterizedTest` + `@ValueSource` (JUnit 5), `@DataProvider` (TestNG), Go table-driven tests, `where` \u002F shared examples (RSpec), `#[rstest]` (Rust), `@ParameterizedTest` + `@MethodSource` (Kotlin), `-ForEach` \u002F `-TestCases` (Pester), `INSTANTIATE_TEST_SUITE_P` (GoogleTest), `SECTION` \u002F `GENERATE` (Catch2), `TEST_CASE_TEMPLATE` (doctest). For a detailed duplication analysis in .NET, use `exp-test-maintainability`. Note: Two tests covering distinct boundary conditions (e.g., zero vs. negative) are NOT duplicates -- separate tests for different edge cases provide clearer failure diagnostics and are a valid practice. |\n| **Giant tests** | Test methods exceeding ~30 lines or testing multiple behaviors at once. Hard to diagnose when they fail. |\n| **Assertion messages that repeat the assertion** | `Assert.AreEqual(expected, actual, \"Expected and actual are not equal\")` \u002F `assert x == y, \"x is not equal to y\"` \u002F `assertEquals(x, y, \"values not equal\")` add no information. Messages should describe the business meaning. |\n| **Missing AAA \u002F Given-When-Then separation** | Arrange\u002FAct\u002FAssert (or Given\u002FWhen\u002FThen for BDD frameworks like RSpec, Kotest behavior specs, Pester) phases are interleaved or indistinguishable. |\n\n#### Low -- Style and hygiene\n\n| Anti-Pattern | What to Look For |\n|---|---|\n| **Unused test infrastructure** | Setup\u002Fteardown hooks that do nothing — `[TestInitialize]`\u002F`[SetUp]`\u002F`[BeforeEach]`, `setUp`\u002F`@BeforeEach`\u002F`@BeforeAll`, `beforeEach`\u002F`beforeAll`, `before(:each)`\u002F`before(:all)`, `BeforeEach`\u002F`BeforeAll` (Pester), `setUpWithError` (XCTest) — and test helper methods that are never called. |\n| **Unmanaged resources** | Test creates disposable\u002Fcloseable resources without cleanup: `HttpClient`\u002F`Stream` without `using` (.NET), file\u002Fconnection without `with` block or `try\u002Ffinally` (Python), `FileInputStream` without `try-with-resources` (Java), `defer file.Close()` missing (Go), connection without `ensure` (Ruby), `Drop` not relied on \u002F forgotten `close` (Rust), missing teardown for temp files \u002F DBs in any language. |\n| **Print debugging** | Leftover `Console.WriteLine` \u002F `Debug.WriteLine` \u002F `print()` \u002F `console.log` \u002F `System.out.println` \u002F `fmt.Println` \u002F `puts` \u002F `dbg!` \u002F `Write-Host` \u002F `std::cout` statements used during test development. |\n| **Inconsistent naming convention** | Mix of naming styles in the same test class\u002Fmodule\u002Ffile (e.g., some use `Method_Scenario_Expected`, others use `ShouldDoSomething`). |\n\n### Step 4: Calibrate severity honestly\n\nBefore reporting, re-check each finding against these severity rules:\n\n- **Critical\u002FHigh**: Only for issues that cause tests to give false confidence or be unreliable. A test that always passes regardless of correctness is Critical. Flaky shared state is High. Missing-await on async assertions is Critical (silent pass).\n- **Medium**: Only for issues that actively harm maintainability -- 5+ nearly-identical tests, truly meaningless names like `Test1` \u002F `test` \u002F `it1`.\n- **Low**: Cosmetic naming mismatches, minor style preferences, assertion messages that could be better. When in doubt, rate Low.\n- **Not an issue** (per-language nuance):\n  - Go and Rust **table-driven loops** with sub-tests (`t.Run` \u002F `for case in cases { ... }`) are *idiomatic*, not \"Conditional Test Logic\". Do NOT flag.\n  - pytest **bare `assert`** is the canonical assertion form, not a missing assertion library. Do NOT flag.\n  - Go tests use `if got != want { t.Errorf(...) }` as canonical equality. Do NOT flag as ad-hoc.\n  - Separate tests for distinct boundary conditions (zero vs. negative vs. null). Do NOT flag as duplicates.\n  - Explicit per-test setup instead of `[TestInitialize]` \u002F `beforeEach` (this *improves* isolation).\n  - Tests that are short and clear but could theoretically be consolidated.\n\nIMPORTANT: If the tests are well-written, say so clearly up front. Do not inflate severity to justify the review. A review that finds zero Critical\u002FHigh issues and only minor Low suggestions is a valid and valuable outcome. Lead with what the tests do well.\n\n### Step 5: Report findings\n\n**Depth bar — a tidy report that is shallower than an unassisted review is a failure.** Before writing, satisfy all four:\n\n1. **Account for every test in scope.** Walk the full list of test methods and fields; a finding table that silently skips tests (or fixtures like an unused `static HttpClient` field) is incomplete. State the number of tests reviewed.\n2. **Make every Critical\u002FHigh fix complete and specific.** Give the replacement assertion with the *exact expected value* (the computed discount, the exact CSV line, the full expected object), not a `\u002F\u002F assert something here` placeholder.\n3. **Name the adjacent gaps the tests should also cover** — untested error paths, boundary values, and round-trip\u002Fculture-sensitivity risks in the same class. These are part of \"what's wrong with my tests\", and omitting them is the most common way this review loses to an unassisted one.\n4. **Keep the report internally consistent.** Summary counts must equal the enumerated findings. Publish a settled conclusion: do all reconsidering before you write, and never leave \"wait, that's wrong\" \u002F \"this should fail but doesn't\" reasoning in the output.\n\nPresent findings in this structure:\n\n1. **Summary** -- Total issues found, broken down by severity (Critical \u002F High \u002F Medium \u002F Low). If tests are well-written, lead with that assessment.\n2. **Critical and High findings** -- List each with:\n   - The anti-pattern name\n   - The specific location (file, method name, line)\n   - A brief explanation of why it's a problem\n   - A concrete fix (show before\u002Fafter code when helpful)\n3. **Medium and Low findings** -- Summarize in a table unless the user wants full detail\n4. **Positive observations** -- Call out things the tests do well (sealed class, specific exception types, data-driven tests, clear AAA structure, proper use of fakes, good naming). Don't only report negatives.\n\n### Step 6: Prioritize recommendations\n\nIf there are many findings, recommend which to fix first:\n\n1. **Critical** -- Fix immediately, these tests may be giving false confidence\n2. **High** -- Fix soon, these cause flakiness or maintenance burden\n3. **Medium\u002FLow** -- Fix opportunistically during related edits\n\n## Validation\n\n- [ ] Every test method in scope is accounted for (reviewed count stated; none silently skipped)\n- [ ] Every finding includes a specific location (not just a general warning)\n- [ ] Every Critical\u002FHigh finding includes a concrete fix with exact expected values\n- [ ] Adjacent untested error paths and boundary values are called out\n- [ ] Summary counts match the enumerated findings\n- [ ] Report covers all categories (assertions, isolation, naming, structure)\n- [ ] Positive observations are included alongside problems\n- [ ] Recommendations are prioritized by severity\n\n## Common Pitfalls\n\n| Pitfall | Solution |\n|---------|----------|\n| Reporting style issues as critical | Naming and formatting are Medium\u002FLow, never Critical |\n| Suggesting rewrites instead of targeted fixes | Show minimal diffs -- change the assertion, not the whole test |\n| Flagging intentional design choices | If `Thread.Sleep` \u002F `time.sleep` \u002F `time.Sleep` is in an integration test testing actual timing, that's not an anti-pattern. Consider context. |\n| Inventing false positives on clean code | If tests follow best practices, say so. A review finding \"0 Critical, 0 High, 1 Low\" is perfectly valid. Don't inflate findings to justify the review. |\n| Flagging separate boundary tests as duplicates | Two tests for zero and negative inputs test different edge cases. Only flag as duplicates when 3+ tests have truly identical bodies differing by a single value. |\n| Rating cosmetic issues as Medium | Naming mismatches (e.g., method name says `ArgumentException` but asserts `ArgumentOutOfRangeException`) are Low, not Medium -- the test still works correctly. |\n| Ignoring the test framework | Use the terminology of the framework you loaded from the language extension; don't describe a pytest suite in MSTest terms. |\n| Missing the forest for the trees | If 80% of tests have no assertions, lead with that systemic issue rather than listing every instance |\n| Trading depth for tidiness | A severity table and positive observations do not substitute for coverage of every test, exact expected values in fixes, and the adjacent error-path\u002Fboundary gaps |\n| Contradicting yourself in the report | Reason first, then write one settled verdict per finding — never emit \"wait, that's wrong\" \u002F \"should fail but doesn't\" reconsiderations |\n| Counts that don't add up | The summary's per-severity totals must match the findings you listed |\n",{"data":38,"body":39},{"name":4,"description":6,"license":28},{"type":40,"children":41},"root",[42,51,57,111,118,148,154,273,279,365,371,378,390,396,532,537,543,548,555,1146,1152,1784,1790,2158,2164,2505,2511,2516,2680,2685,2691,2701,2768,2773,2839,2845,2850,2883,2889,2970,2976],{"type":43,"tag":44,"props":45,"children":47},"element","h1",{"id":46},"test-anti-pattern-detection",[48],{"type":49,"value":50},"text","Test Anti-Pattern Detection",{"type":43,"tag":52,"props":53,"children":54},"p",{},[55],{"type":49,"value":56},"Quick, pragmatic analysis of test code in any supported language for anti-patterns and quality issues that undermine test reliability, maintainability, and diagnostic value.",{"type":43,"tag":58,"props":59,"children":60},"blockquote",{},[61],{"type":43,"tag":52,"props":62,"children":63},{},[64,70,72,79,81,87,89,95,96,102,103,109],{"type":43,"tag":65,"props":66,"children":67},"strong",{},[68],{"type":49,"value":69},"Language-specific guidance",{"type":49,"value":71},": Call the ",{"type":43,"tag":73,"props":74,"children":76},"code",{"className":75},[],[77],{"type":49,"value":78},"test-analysis-extensions",{"type":49,"value":80}," skill to discover available extension files, then read the file matching the target codebase (e.g., ",{"type":43,"tag":73,"props":82,"children":84},{"className":83},[],[85],{"type":49,"value":86},"extensions\u002Fdotnet.md",{"type":49,"value":88},", ",{"type":43,"tag":73,"props":90,"children":92},{"className":91},[],[93],{"type":49,"value":94},"extensions\u002Fpython.md",{"type":49,"value":88},{"type":43,"tag":73,"props":97,"children":99},{"className":98},[],[100],{"type":49,"value":101},"extensions\u002Ftypescript.md",{"type":49,"value":88},{"type":43,"tag":73,"props":104,"children":106},{"className":105},[],[107],{"type":49,"value":108},"extensions\u002Fgo.md",{"type":49,"value":110},"). The extension file tells you which sleep \u002F time \u002F random \u002F skip \u002F setup-teardown \u002F mystery-guest APIs to look for in that language.",{"type":43,"tag":112,"props":113,"children":115},"h2",{"id":114},"when-to-use",[116],{"type":49,"value":117},"When to Use",{"type":43,"tag":119,"props":120,"children":121},"ul",{},[122,128,133,138,143],{"type":43,"tag":123,"props":124,"children":125},"li",{},[126],{"type":49,"value":127},"User asks to review test quality or find test smells",{"type":43,"tag":123,"props":129,"children":130},{},[131],{"type":49,"value":132},"User wants to know why tests are flaky or unreliable",{"type":43,"tag":123,"props":134,"children":135},{},[136],{"type":49,"value":137},"User asks \"are my tests good?\" or \"what's wrong with my tests?\"",{"type":43,"tag":123,"props":139,"children":140},{},[141],{"type":49,"value":142},"User requests a test audit or test code review",{"type":43,"tag":123,"props":144,"children":145},{},[146],{"type":49,"value":147},"User wants to improve existing test code",{"type":43,"tag":112,"props":149,"children":151},{"id":150},"when-not-to-use",[152],{"type":49,"value":153},"When Not to Use",{"type":43,"tag":119,"props":155,"children":156},{},[157,178,183,203,238,251,256,261],{"type":43,"tag":123,"props":158,"children":159},{},[160,162,168,170,176],{"type":49,"value":161},"User wants to write new tests from scratch (use ",{"type":43,"tag":73,"props":163,"children":165},{"className":164},[],[166],{"type":49,"value":167},"code-testing-agent",{"type":49,"value":169}," for any language, or ",{"type":43,"tag":73,"props":171,"children":173},{"className":172},[],[174],{"type":49,"value":175},"writing-mstest-tests",{"type":49,"value":177}," for MSTest specifically)",{"type":43,"tag":123,"props":179,"children":180},{},[181],{"type":49,"value":182},"User wants direct implementation fixes rather than a diagnostic review (use the relevant write\u002Fedit skill)",{"type":43,"tag":123,"props":184,"children":185},{},[186,188,194,196,201],{"type":49,"value":187},"User asks to fix swapped ",{"type":43,"tag":73,"props":189,"children":191},{"className":190},[],[192],{"type":49,"value":193},"Assert.AreEqual",{"type":49,"value":195}," argument order in MSTest (use ",{"type":43,"tag":73,"props":197,"children":199},{"className":198},[],[200],{"type":49,"value":175},{"type":49,"value":202},")",{"type":43,"tag":123,"props":204,"children":205},{},[206,208,214,216,222,224,230,232,237],{"type":49,"value":207},"User asks to convert MSTest ",{"type":43,"tag":73,"props":209,"children":211},{"className":210},[],[212],{"type":49,"value":213},"DynamicData",{"type":49,"value":215}," from ",{"type":43,"tag":73,"props":217,"children":219},{"className":218},[],[220],{"type":49,"value":221},"IEnumerable\u003Cobject[]>",{"type":49,"value":223}," to ",{"type":43,"tag":73,"props":225,"children":227},{"className":226},[],[228],{"type":49,"value":229},"ValueTuple",{"type":49,"value":231}," (use ",{"type":43,"tag":73,"props":233,"children":235},{"className":234},[],[236],{"type":49,"value":175},{"type":49,"value":202},{"type":43,"tag":123,"props":239,"children":240},{},[241,243,249],{"type":49,"value":242},"User wants to run or execute tests (use ",{"type":43,"tag":73,"props":244,"children":246},{"className":245},[],[247],{"type":49,"value":248},"run-tests",{"type":49,"value":250}," for .NET)",{"type":43,"tag":123,"props":252,"children":253},{},[254],{"type":49,"value":255},"User wants to migrate between test frameworks or versions (use migration skills)",{"type":43,"tag":123,"props":257,"children":258},{},[259],{"type":49,"value":260},"User wants to measure code coverage (out of scope)",{"type":43,"tag":123,"props":262,"children":263},{},[264,266,272],{"type":49,"value":265},"User wants a deep formal test smell audit with academic taxonomy and extended catalog (use ",{"type":43,"tag":73,"props":267,"children":269},{"className":268},[],[270],{"type":49,"value":271},"test-smell-detection",{"type":49,"value":202},{"type":43,"tag":112,"props":274,"children":276},{"id":275},"inputs",[277],{"type":49,"value":278},"Inputs",{"type":43,"tag":280,"props":281,"children":282},"table",{},[283,307],{"type":43,"tag":284,"props":285,"children":286},"thead",{},[287],{"type":43,"tag":288,"props":289,"children":290},"tr",{},[291,297,302],{"type":43,"tag":292,"props":293,"children":294},"th",{},[295],{"type":49,"value":296},"Input",{"type":43,"tag":292,"props":298,"children":299},{},[300],{"type":49,"value":301},"Required",{"type":43,"tag":292,"props":303,"children":304},{},[305],{"type":49,"value":306},"Description",{"type":43,"tag":308,"props":309,"children":310},"tbody",{},[311,330,348],{"type":43,"tag":288,"props":312,"children":313},{},[314,320,325],{"type":43,"tag":315,"props":316,"children":317},"td",{},[318],{"type":49,"value":319},"Test code",{"type":43,"tag":315,"props":321,"children":322},{},[323],{"type":49,"value":324},"Yes",{"type":43,"tag":315,"props":326,"children":327},{},[328],{"type":49,"value":329},"One or more test files or classes to analyze",{"type":43,"tag":288,"props":331,"children":332},{},[333,338,343],{"type":43,"tag":315,"props":334,"children":335},{},[336],{"type":49,"value":337},"Production code",{"type":43,"tag":315,"props":339,"children":340},{},[341],{"type":49,"value":342},"No",{"type":43,"tag":315,"props":344,"children":345},{},[346],{"type":49,"value":347},"The code under test, for context on what tests should verify",{"type":43,"tag":288,"props":349,"children":350},{},[351,356,360],{"type":43,"tag":315,"props":352,"children":353},{},[354],{"type":49,"value":355},"Specific concern",{"type":43,"tag":315,"props":357,"children":358},{},[359],{"type":49,"value":342},{"type":43,"tag":315,"props":361,"children":362},{},[363],{"type":49,"value":364},"A focused area like \"flakiness\" or \"naming\" to narrow the review",{"type":43,"tag":112,"props":366,"children":368},{"id":367},"workflow",[369],{"type":49,"value":370},"Workflow",{"type":43,"tag":372,"props":373,"children":375},"h3",{"id":374},"step-1-detect-language-and-load-extension",[376],{"type":49,"value":377},"Step 1: Detect language and load extension",{"type":43,"tag":52,"props":379,"children":380},{},[381,383,388],{"type":49,"value":382},"Identify the target codebase's language and test framework. Call the ",{"type":43,"tag":73,"props":384,"children":386},{"className":385},[],[387],{"type":49,"value":78},{"type":49,"value":389}," skill and read the matching extension file. The extension file documents framework-specific anti-pattern markers — what counts as a sleep\u002Fwait, a test marker, a skip, a setup\u002Fteardown, a shared-state hot spot, and an integration boundary — so this skill stays language-neutral.",{"type":43,"tag":372,"props":391,"children":393},{"id":392},"step-2-gather-the-test-code",[394],{"type":49,"value":395},"Step 2: Gather the test code",{"type":43,"tag":52,"props":397,"children":398},{},[399,401,407,409,415,416,422,424,430,432,438,440,446,447,453,455,461,462,468,470,476,477,483,485,491,493,499,501,507,508,514,516,522,524,530],{"type":49,"value":400},"Read the test files the user wants reviewed. If the user points to a directory or project, scan for all test files using the discovery markers in the loaded language extension file (e.g., ",{"type":43,"tag":73,"props":402,"children":404},{"className":403},[],[405],{"type":49,"value":406},"[TestClass]",{"type":49,"value":408},"\u002F",{"type":43,"tag":73,"props":410,"children":412},{"className":411},[],[413],{"type":49,"value":414},"[Fact]",{"type":49,"value":408},{"type":43,"tag":73,"props":417,"children":419},{"className":418},[],[420],{"type":49,"value":421},"[Test]",{"type":49,"value":423}," for .NET, ",{"type":43,"tag":73,"props":425,"children":427},{"className":426},[],[428],{"type":49,"value":429},"test_*.py",{"type":49,"value":431}," \u002F ",{"type":43,"tag":73,"props":433,"children":435},{"className":434},[],[436],{"type":49,"value":437},"def test_*",{"type":49,"value":439}," for pytest, ",{"type":43,"tag":73,"props":441,"children":443},{"className":442},[],[444],{"type":49,"value":445},"*.test.ts",{"type":49,"value":431},{"type":43,"tag":73,"props":448,"children":450},{"className":449},[],[451],{"type":49,"value":452},"it()",{"type":49,"value":454}," for Jest, ",{"type":43,"tag":73,"props":456,"children":458},{"className":457},[],[459],{"type":49,"value":460},"*Test.java",{"type":49,"value":431},{"type":43,"tag":73,"props":463,"children":465},{"className":464},[],[466],{"type":49,"value":467},"@Test",{"type":49,"value":469}," for JUnit, ",{"type":43,"tag":73,"props":471,"children":473},{"className":472},[],[474],{"type":49,"value":475},"*_test.go",{"type":49,"value":431},{"type":43,"tag":73,"props":478,"children":480},{"className":479},[],[481],{"type":49,"value":482},"func TestXxx",{"type":49,"value":484}," for Go, ",{"type":43,"tag":73,"props":486,"children":488},{"className":487},[],[489],{"type":49,"value":490},"*_spec.rb",{"type":49,"value":492}," for RSpec, ",{"type":43,"tag":73,"props":494,"children":496},{"className":495},[],[497],{"type":49,"value":498},"#[test]",{"type":49,"value":500}," for Rust, ",{"type":43,"tag":73,"props":502,"children":504},{"className":503},[],[505],{"type":49,"value":506},"*.Tests.ps1",{"type":49,"value":431},{"type":43,"tag":73,"props":509,"children":511},{"className":510},[],[512],{"type":49,"value":513},"Describe",{"type":49,"value":515}," for Pester, ",{"type":43,"tag":73,"props":517,"children":519},{"className":518},[],[520],{"type":49,"value":521},"TEST(...)",{"type":49,"value":523}," for GoogleTest, ",{"type":43,"tag":73,"props":525,"children":527},{"className":526},[],[528],{"type":49,"value":529},"TEST_CASE(...)",{"type":49,"value":531}," for Catch2\u002Fdoctest).",{"type":43,"tag":52,"props":533,"children":534},{},[535],{"type":49,"value":536},"If production code is available, read it too -- this is critical for detecting tests that are coupled to implementation details rather than behavior.",{"type":43,"tag":372,"props":538,"children":540},{"id":539},"step-3-scan-for-anti-patterns",[541],{"type":49,"value":542},"Step 3: Scan for anti-patterns",{"type":43,"tag":52,"props":544,"children":545},{},[546],{"type":49,"value":547},"Check each test file against the anti-pattern catalog below. Report findings grouped by severity. The examples are .NET-centric but the patterns generalize — use the loaded language extension file to map each pattern to the framework you are auditing.",{"type":43,"tag":549,"props":550,"children":552},"h4",{"id":551},"critical-tests-that-give-false-confidence",[553],{"type":49,"value":554},"Critical -- Tests that give false confidence",{"type":43,"tag":280,"props":556,"children":557},{},[558,574],{"type":43,"tag":284,"props":559,"children":560},{},[561],{"type":43,"tag":288,"props":562,"children":563},{},[564,569],{"type":43,"tag":292,"props":565,"children":566},{},[567],{"type":49,"value":568},"Anti-Pattern",{"type":43,"tag":292,"props":570,"children":571},{},[572],{"type":49,"value":573},"What to Look For",{"type":43,"tag":308,"props":575,"children":576},{},[577,693,774,828,902,995,1073,1130],{"type":43,"tag":288,"props":578,"children":579},{},[580,588],{"type":43,"tag":315,"props":581,"children":582},{},[583],{"type":43,"tag":65,"props":584,"children":585},{},[586],{"type":49,"value":587},"No assertions",{"type":43,"tag":315,"props":589,"children":590},{},[591,593,599,601,607,609,615,617,623,625,631,632,638,640,646,647,653,655,661,663,669,671,677,678,684,685,691],{"type":49,"value":592},"Test methods that execute code but never assert anything. A passing test without assertions proves nothing. In .NET look for missing ",{"type":43,"tag":73,"props":594,"children":596},{"className":595},[],[597],{"type":49,"value":598},"Assert.*",{"type":49,"value":600},"; in pytest a function with no ",{"type":43,"tag":73,"props":602,"children":604},{"className":603},[],[605],{"type":49,"value":606},"assert",{"type":49,"value":608}," and no ",{"type":43,"tag":73,"props":610,"children":612},{"className":611},[],[613],{"type":49,"value":614},"pytest.raises",{"type":49,"value":616},"; in Jest no ",{"type":43,"tag":73,"props":618,"children":620},{"className":619},[],[621],{"type":49,"value":622},"expect(...)",{"type":49,"value":624},"; in JUnit no ",{"type":43,"tag":73,"props":626,"children":628},{"className":627},[],[629],{"type":49,"value":630},"assert*",{"type":49,"value":408},{"type":43,"tag":73,"props":633,"children":635},{"className":634},[],[636],{"type":49,"value":637},"assertThat",{"type":49,"value":639},"; in Go a test that never calls ",{"type":43,"tag":73,"props":641,"children":643},{"className":642},[],[644],{"type":49,"value":645},"t.Error*",{"type":49,"value":88},{"type":43,"tag":73,"props":648,"children":650},{"className":649},[],[651],{"type":49,"value":652},"t.Fatal*",{"type":49,"value":654},", or testify; in RSpec a block with no ",{"type":43,"tag":73,"props":656,"children":658},{"className":657},[],[659],{"type":49,"value":660},"expect",{"type":49,"value":662},"; in Pester no ",{"type":43,"tag":73,"props":664,"children":666},{"className":665},[],[667],{"type":49,"value":668},"Should",{"type":49,"value":670},". Mock-call verifications (",{"type":43,"tag":73,"props":672,"children":674},{"className":673},[],[675],{"type":49,"value":676},"verify(mock)",{"type":49,"value":88},{"type":43,"tag":73,"props":679,"children":681},{"className":680},[],[682],{"type":49,"value":683},"expect(mock).toHaveBeenCalled",{"type":49,"value":88},{"type":43,"tag":73,"props":686,"children":688},{"className":687},[],[689],{"type":49,"value":690},"Should -Invoke",{"type":49,"value":692},") are real assertions.",{"type":43,"tag":288,"props":694,"children":695},{},[696,704],{"type":43,"tag":315,"props":697,"children":698},{},[699],{"type":43,"tag":65,"props":700,"children":701},{},[702],{"type":49,"value":703},"Missing await on async assertions (JS\u002FTS, .NET, Python, Kotlin, Swift)",{"type":43,"tag":315,"props":705,"children":706},{},[707,713,715,721,722,728,729,735,737,743,745,751,752,757,759,765,767,772],{"type":43,"tag":73,"props":708,"children":710},{"className":709},[],[711],{"type":49,"value":712},"expect(promise).resolves.toBe(x)",{"type":49,"value":714}," without ",{"type":43,"tag":73,"props":716,"children":718},{"className":717},[],[719],{"type":49,"value":720},"await",{"type":49,"value":408},{"type":43,"tag":73,"props":723,"children":725},{"className":724},[],[726],{"type":49,"value":727},"return",{"type":49,"value":88},{"type":43,"tag":73,"props":730,"children":732},{"className":731},[],[733],{"type":49,"value":734},"pytest-asyncio",{"type":49,"value":736}," test with un-awaited coroutine, ",{"type":43,"tag":73,"props":738,"children":740},{"className":739},[],[741],{"type":49,"value":742},"async Task",{"type":49,"value":744}," xUnit test calling ",{"type":43,"tag":73,"props":746,"children":748},{"className":747},[],[749],{"type":49,"value":750},"Assert.ThrowsAsync",{"type":49,"value":714},{"type":43,"tag":73,"props":753,"children":755},{"className":754},[],[756],{"type":49,"value":720},{"type":49,"value":758},", Kotest suspending test without ",{"type":43,"tag":73,"props":760,"children":762},{"className":761},[],[763],{"type":49,"value":764},"runTest",{"type":49,"value":766},", Swift Testing async test without ",{"type":43,"tag":73,"props":768,"children":770},{"className":769},[],[771],{"type":49,"value":720},{"type":49,"value":773},". These tests silently pass even when the underlying assertion would have failed.",{"type":43,"tag":288,"props":775,"children":776},{},[777,785],{"type":43,"tag":315,"props":778,"children":779},{},[780],{"type":43,"tag":65,"props":781,"children":782},{},[783],{"type":49,"value":784},"Coverage touching",{"type":43,"tag":315,"props":786,"children":787},{},[788,790,796,798,804,805,811,812,818,820,826],{"type":49,"value":789},"Test class that methodically calls every public member on a type — often in alphabetical or declaration order — without asserting meaningful outcomes. Each test typically does ",{"type":43,"tag":73,"props":791,"children":793},{"className":792},[],[794],{"type":49,"value":795},"var result = sut.MethodName(...)",{"type":49,"value":797}," (or ",{"type":43,"tag":73,"props":799,"children":801},{"className":800},[],[802],{"type":49,"value":803},"result = sut.method_name(...)",{"type":49,"value":88},{"type":43,"tag":73,"props":806,"children":808},{"className":807},[],[809],{"type":49,"value":810},"sut.methodName()",{"type":49,"value":88},{"type":43,"tag":73,"props":813,"children":815},{"className":814},[],[816],{"type":49,"value":817},"sut.MethodName(t)",{"type":49,"value":819},") with no assertion, or only a trivial null\u002FNone\u002Fnil check. The intent is to inflate code-coverage metrics rather than verify behavior. Distinct from a single assertion-free test: the pattern is ",{"type":43,"tag":821,"props":822,"children":823},"em",{},[824],{"type":49,"value":825},"systematic",{"type":49,"value":827}," coverage of the surface area with no real verification.",{"type":43,"tag":288,"props":829,"children":830},{},[831,839],{"type":43,"tag":315,"props":832,"children":833},{},[834],{"type":43,"tag":65,"props":835,"children":836},{},[837],{"type":49,"value":838},"Self-referential assertion",{"type":43,"tag":315,"props":840,"children":841},{},[842,844,850,851,857,858,864,865,871,873,879,880,886,887,893,895,900],{"type":49,"value":843},"Asserts that the output of an operation equals its input when the operation is expected to be an identity or no-op, e.g. ",{"type":43,"tag":73,"props":845,"children":847},{"className":846},[],[848],{"type":49,"value":849},"Assert.AreEqual(input, Parse(input.ToString()))",{"type":49,"value":88},{"type":43,"tag":73,"props":852,"children":854},{"className":853},[],[855],{"type":49,"value":856},"assert input == parse(str(input))",{"type":49,"value":88},{"type":43,"tag":73,"props":859,"children":861},{"className":860},[],[862],{"type":49,"value":863},"expect(parse(input.toString())).toBe(input)",{"type":49,"value":88},{"type":43,"tag":73,"props":866,"children":868},{"className":867},[],[869],{"type":49,"value":870},"assert.Equal(t, input, parse(input))",{"type":49,"value":872},". Also flags ",{"type":43,"tag":73,"props":874,"children":876},{"className":875},[],[877],{"type":49,"value":878},"Assert.AreEqual(dto.Name, dto.Name)",{"type":49,"value":431},{"type":43,"tag":73,"props":881,"children":883},{"className":882},[],[884],{"type":49,"value":885},"assert dto.name == dto.name",{"type":49,"value":431},{"type":43,"tag":73,"props":888,"children":890},{"className":889},[],[891],{"type":49,"value":892},"expect(dto.name).toBe(dto.name)",{"type":49,"value":894}," (asserting a field against itself). The test is tautological — it can only fail if the round-trip is broken, but never verifies that a ",{"type":43,"tag":821,"props":896,"children":897},{},[898],{"type":49,"value":899},"transformation",{"type":49,"value":901}," actually happened.",{"type":43,"tag":288,"props":903,"children":904},{},[905,913],{"type":43,"tag":315,"props":906,"children":907},{},[908],{"type":43,"tag":65,"props":909,"children":910},{},[911],{"type":49,"value":912},"Swallowed exceptions",{"type":43,"tag":315,"props":914,"children":915},{},[916,922,923,929,931,937,939,945,947,953,955,961,963,969,971,977,979,985,987,993],{"type":43,"tag":73,"props":917,"children":919},{"className":918},[],[920],{"type":49,"value":921},"try { ... } catch { }",{"type":49,"value":88},{"type":43,"tag":73,"props":924,"children":926},{"className":925},[],[927],{"type":49,"value":928},"catch (Exception)",{"type":49,"value":930}," without rethrowing or asserting (.NET); bare ",{"type":43,"tag":73,"props":932,"children":934},{"className":933},[],[935],{"type":49,"value":936},"except:",{"type":49,"value":938}," or ",{"type":43,"tag":73,"props":940,"children":942},{"className":941},[],[943],{"type":49,"value":944},"except Exception:",{"type":49,"value":946}," with ",{"type":43,"tag":73,"props":948,"children":950},{"className":949},[],[951],{"type":49,"value":952},"pass",{"type":49,"value":954}," (Python); ",{"type":43,"tag":73,"props":956,"children":958},{"className":957},[],[959],{"type":49,"value":960},"try { ... } catch (e) {}",{"type":49,"value":962}," (JS\u002FTS\u002FJava); ",{"type":43,"tag":73,"props":964,"children":966},{"className":965},[],[967],{"type":49,"value":968},"defer recover()",{"type":49,"value":970}," without re-panic and no assertion (Go); ",{"type":43,"tag":73,"props":972,"children":974},{"className":973},[],[975],{"type":49,"value":976},"rescue StandardError",{"type":49,"value":978}," with no assertion (Ruby); ",{"type":43,"tag":73,"props":980,"children":982},{"className":981},[],[983],{"type":49,"value":984},"Result::unwrap_or(...)",{"type":49,"value":986}," swallowing errors in a test (Rust); empty ",{"type":43,"tag":73,"props":988,"children":990},{"className":989},[],[991],{"type":49,"value":992},"catch",{"type":49,"value":994}," block (Kotlin\u002FSwift).",{"type":43,"tag":288,"props":996,"children":997},{},[998,1006],{"type":43,"tag":315,"props":999,"children":1000},{},[1001],{"type":43,"tag":65,"props":1002,"children":1003},{},[1004],{"type":49,"value":1005},"Assert in catch block only",{"type":43,"tag":315,"props":1007,"children":1008},{},[1009,1015,1017,1023,1024,1029,1030,1036,1037,1043,1044,1050,1051,1057,1058,1064,1065,1071],{"type":43,"tag":73,"props":1010,"children":1012},{"className":1011},[],[1013],{"type":49,"value":1014},"try { Act(); } catch (Exception ex) { Assert.Fail(ex.Message); }",{"type":49,"value":1016}," (and equivalents in other languages) -- use ",{"type":43,"tag":73,"props":1018,"children":1020},{"className":1019},[],[1021],{"type":49,"value":1022},"Assert.ThrowsException",{"type":49,"value":431},{"type":43,"tag":73,"props":1025,"children":1027},{"className":1026},[],[1028],{"type":49,"value":614},{"type":49,"value":431},{"type":43,"tag":73,"props":1031,"children":1033},{"className":1032},[],[1034],{"type":49,"value":1035},"expect(fn).toThrow",{"type":49,"value":431},{"type":43,"tag":73,"props":1038,"children":1040},{"className":1039},[],[1041],{"type":49,"value":1042},"assertThrows",{"type":49,"value":431},{"type":43,"tag":73,"props":1045,"children":1047},{"className":1046},[],[1048],{"type":49,"value":1049},"assert.Error(t, err)",{"type":49,"value":431},{"type":43,"tag":73,"props":1052,"children":1054},{"className":1053},[],[1055],{"type":49,"value":1056},"#[should_panic]",{"type":49,"value":431},{"type":43,"tag":73,"props":1059,"children":1061},{"className":1060},[],[1062],{"type":49,"value":1063},"Should -Throw",{"type":49,"value":431},{"type":43,"tag":73,"props":1066,"children":1068},{"className":1067},[],[1069],{"type":49,"value":1070},"EXPECT_THROW",{"type":49,"value":1072}," instead. The test passes when no exception is thrown even if the result is wrong.",{"type":43,"tag":288,"props":1074,"children":1075},{},[1076,1084],{"type":43,"tag":315,"props":1077,"children":1078},{},[1079],{"type":43,"tag":65,"props":1080,"children":1081},{},[1082],{"type":49,"value":1083},"Always-true assertions",{"type":43,"tag":315,"props":1085,"children":1086},{},[1087,1093,1094,1100,1101,1107,1108,1114,1115,1121,1122,1128],{"type":43,"tag":73,"props":1088,"children":1090},{"className":1089},[],[1091],{"type":49,"value":1092},"Assert.IsTrue(true)",{"type":49,"value":88},{"type":43,"tag":73,"props":1095,"children":1097},{"className":1096},[],[1098],{"type":49,"value":1099},"Assert.AreEqual(x, x)",{"type":49,"value":88},{"type":43,"tag":73,"props":1102,"children":1104},{"className":1103},[],[1105],{"type":49,"value":1106},"assert True",{"type":49,"value":88},{"type":43,"tag":73,"props":1109,"children":1111},{"className":1110},[],[1112],{"type":49,"value":1113},"expect(true).toBe(true)",{"type":49,"value":88},{"type":43,"tag":73,"props":1116,"children":1118},{"className":1117},[],[1119],{"type":49,"value":1120},"assert.True(t, true)",{"type":49,"value":88},{"type":43,"tag":73,"props":1123,"children":1125},{"className":1124},[],[1126],{"type":49,"value":1127},"assert!(true)",{"type":49,"value":1129},", or conditions that can never fail.",{"type":43,"tag":288,"props":1131,"children":1132},{},[1133,1141],{"type":43,"tag":315,"props":1134,"children":1135},{},[1136],{"type":43,"tag":65,"props":1137,"children":1138},{},[1139],{"type":49,"value":1140},"Commented-out assertions",{"type":43,"tag":315,"props":1142,"children":1143},{},[1144],{"type":49,"value":1145},"Assertions that were disabled but the test still runs, giving the illusion of coverage.",{"type":43,"tag":549,"props":1147,"children":1149},{"id":1148},"high-tests-likely-to-cause-pain",[1150],{"type":49,"value":1151},"High -- Tests likely to cause pain",{"type":43,"tag":280,"props":1153,"children":1154},{},[1155,1169],{"type":43,"tag":284,"props":1156,"children":1157},{},[1158],{"type":43,"tag":288,"props":1159,"children":1160},{},[1161,1165],{"type":43,"tag":292,"props":1162,"children":1163},{},[1164],{"type":49,"value":568},{"type":43,"tag":292,"props":1166,"children":1167},{},[1168],{"type":49,"value":573},{"type":43,"tag":308,"props":1170,"children":1171},{},[1172,1446,1565,1620,1683],{"type":43,"tag":288,"props":1173,"children":1174},{},[1175,1183],{"type":43,"tag":315,"props":1176,"children":1177},{},[1178],{"type":43,"tag":65,"props":1179,"children":1180},{},[1181],{"type":49,"value":1182},"Flakiness indicators",{"type":43,"tag":315,"props":1184,"children":1185},{},[1186,1188,1194,1195,1201,1203,1209,1211,1217,1218,1224,1226,1232,1234,1240,1242,1248,1250,1256,1258,1264,1266,1272,1274,1280,1281,1287,1288,1294,1295,1301,1302,1308,1309,1315,1316,1322,1323,1329,1330,1336,1337,1343,1344,1350,1351,1357,1358,1364,1365,1371,1373,1379,1380,1386,1387,1393,1394,1400,1401,1406,1407,1413,1415,1421,1423,1429,1431,1437,1438,1444],{"type":49,"value":1187},"Wall-clock sleeps\u002Fwaits used for synchronization: ",{"type":43,"tag":73,"props":1189,"children":1191},{"className":1190},[],[1192],{"type":49,"value":1193},"Thread.Sleep",{"type":49,"value":431},{"type":43,"tag":73,"props":1196,"children":1198},{"className":1197},[],[1199],{"type":49,"value":1200},"Task.Delay",{"type":49,"value":1202}," (.NET), ",{"type":43,"tag":73,"props":1204,"children":1206},{"className":1205},[],[1207],{"type":49,"value":1208},"time.sleep",{"type":49,"value":1210}," (Python), ",{"type":43,"tag":73,"props":1212,"children":1214},{"className":1213},[],[1215],{"type":49,"value":1216},"setTimeout",{"type":49,"value":431},{"type":43,"tag":73,"props":1219,"children":1221},{"className":1220},[],[1222],{"type":49,"value":1223},"await new Promise(r => setTimeout(...))",{"type":49,"value":1225}," (JS\u002FTS), ",{"type":43,"tag":73,"props":1227,"children":1229},{"className":1228},[],[1230],{"type":49,"value":1231},"Thread.sleep",{"type":49,"value":1233}," (Java\u002FKotlin), ",{"type":43,"tag":73,"props":1235,"children":1237},{"className":1236},[],[1238],{"type":49,"value":1239},"time.Sleep",{"type":49,"value":1241}," (Go), ",{"type":43,"tag":73,"props":1243,"children":1245},{"className":1244},[],[1246],{"type":49,"value":1247},"sleep",{"type":49,"value":1249}," (Ruby\u002FBash), ",{"type":43,"tag":73,"props":1251,"children":1253},{"className":1252},[],[1254],{"type":49,"value":1255},"std::thread::sleep",{"type":49,"value":1257}," (Rust), ",{"type":43,"tag":73,"props":1259,"children":1261},{"className":1260},[],[1262],{"type":49,"value":1263},"Start-Sleep",{"type":49,"value":1265}," (Pester), ",{"type":43,"tag":73,"props":1267,"children":1269},{"className":1268},[],[1270],{"type":49,"value":1271},"std::this_thread::sleep_for",{"type":49,"value":1273}," (C++). Wall-clock reads without abstraction: ",{"type":43,"tag":73,"props":1275,"children":1277},{"className":1276},[],[1278],{"type":49,"value":1279},"DateTime.Now",{"type":49,"value":408},{"type":43,"tag":73,"props":1282,"children":1284},{"className":1283},[],[1285],{"type":49,"value":1286},"UtcNow",{"type":49,"value":88},{"type":43,"tag":73,"props":1289,"children":1291},{"className":1290},[],[1292],{"type":49,"value":1293},"datetime.now()",{"type":49,"value":408},{"type":43,"tag":73,"props":1296,"children":1298},{"className":1297},[],[1299],{"type":49,"value":1300},"datetime.utcnow()",{"type":49,"value":88},{"type":43,"tag":73,"props":1303,"children":1305},{"className":1304},[],[1306],{"type":49,"value":1307},"Date.now()",{"type":49,"value":431},{"type":43,"tag":73,"props":1310,"children":1312},{"className":1311},[],[1313],{"type":49,"value":1314},"new Date()",{"type":49,"value":88},{"type":43,"tag":73,"props":1317,"children":1319},{"className":1318},[],[1320],{"type":49,"value":1321},"System.currentTimeMillis()",{"type":49,"value":88},{"type":43,"tag":73,"props":1324,"children":1326},{"className":1325},[],[1327],{"type":49,"value":1328},"time.Now()",{"type":49,"value":88},{"type":43,"tag":73,"props":1331,"children":1333},{"className":1332},[],[1334],{"type":49,"value":1335},"Time.now",{"type":49,"value":88},{"type":43,"tag":73,"props":1338,"children":1340},{"className":1339},[],[1341],{"type":49,"value":1342},"Instant::now()",{"type":49,"value":88},{"type":43,"tag":73,"props":1345,"children":1347},{"className":1346},[],[1348],{"type":49,"value":1349},"Date()",{"type":49,"value":408},{"type":43,"tag":73,"props":1352,"children":1354},{"className":1353},[],[1355],{"type":49,"value":1356},"Date.now",{"type":49,"value":88},{"type":43,"tag":73,"props":1359,"children":1361},{"className":1360},[],[1362],{"type":49,"value":1363},"Get-Date",{"type":49,"value":88},{"type":43,"tag":73,"props":1366,"children":1368},{"className":1367},[],[1369],{"type":49,"value":1370},"std::chrono::system_clock::now",{"type":49,"value":1372},". Unseeded randomness: ",{"type":43,"tag":73,"props":1374,"children":1376},{"className":1375},[],[1377],{"type":49,"value":1378},"new Random()",{"type":49,"value":88},{"type":43,"tag":73,"props":1381,"children":1383},{"className":1382},[],[1384],{"type":49,"value":1385},"random.random()",{"type":49,"value":408},{"type":43,"tag":73,"props":1388,"children":1390},{"className":1389},[],[1391],{"type":49,"value":1392},"random.randint()",{"type":49,"value":88},{"type":43,"tag":73,"props":1395,"children":1397},{"className":1396},[],[1398],{"type":49,"value":1399},"Math.random()",{"type":49,"value":88},{"type":43,"tag":73,"props":1402,"children":1404},{"className":1403},[],[1405],{"type":49,"value":1378},{"type":49,"value":1233},{"type":43,"tag":73,"props":1408,"children":1410},{"className":1409},[],[1411],{"type":49,"value":1412},"rand.Int()",{"type":49,"value":1414}," without seed, ",{"type":43,"tag":73,"props":1416,"children":1418},{"className":1417},[],[1419],{"type":49,"value":1420},"rand",{"type":49,"value":1422}," (Ruby), ",{"type":43,"tag":73,"props":1424,"children":1426},{"className":1425},[],[1427],{"type":49,"value":1428},"rand::random()",{"type":49,"value":1430}," (Rust). Environment-dependent paths (hard-coded ",{"type":43,"tag":73,"props":1432,"children":1434},{"className":1433},[],[1435],{"type":49,"value":1436},"C:\\...",{"type":49,"value":88},{"type":43,"tag":73,"props":1439,"children":1441},{"className":1440},[],[1442],{"type":49,"value":1443},"\u002Ftmp\u002F...",{"type":49,"value":1445},", network hosts).",{"type":43,"tag":288,"props":1447,"children":1448},{},[1449,1457],{"type":43,"tag":315,"props":1450,"children":1451},{},[1452],{"type":43,"tag":65,"props":1453,"children":1454},{},[1455],{"type":49,"value":1456},"Test ordering dependency",{"type":43,"tag":315,"props":1458,"children":1459},{},[1460,1462,1468,1469,1475,1476,1482,1483,1489,1490,1496,1497,1503,1505,1511,1513,1519,1520,1526,1528,1534,1536,1542,1543,1549,1550,1556,1557,1563],{"type":49,"value":1461},"Static\u002Fglobal mutable state modified across tests; setup that doesn't fully reset state (",{"type":43,"tag":73,"props":1463,"children":1465},{"className":1464},[],[1466],{"type":49,"value":1467},"[TestInitialize]",{"type":49,"value":88},{"type":43,"tag":73,"props":1470,"children":1472},{"className":1471},[],[1473],{"type":49,"value":1474},"setUp",{"type":49,"value":88},{"type":43,"tag":73,"props":1477,"children":1479},{"className":1478},[],[1480],{"type":49,"value":1481},"beforeEach",{"type":49,"value":88},{"type":43,"tag":73,"props":1484,"children":1486},{"className":1485},[],[1487],{"type":49,"value":1488},"before(:each)",{"type":49,"value":88},{"type":43,"tag":73,"props":1491,"children":1493},{"className":1492},[],[1494],{"type":49,"value":1495},"BeforeEach",{"type":49,"value":88},{"type":43,"tag":73,"props":1498,"children":1500},{"className":1499},[],[1501],{"type":49,"value":1502},"t.Cleanup",{"type":49,"value":1504},"); tests that fail when run individually but pass in suite (or vice versa). Examples per language: ",{"type":43,"tag":73,"props":1506,"children":1508},{"className":1507},[],[1509],{"type":49,"value":1510},"static",{"type":49,"value":1512}," fields (.NET\u002FJava), module-level globals (Python), top-level ",{"type":43,"tag":73,"props":1514,"children":1516},{"className":1515},[],[1517],{"type":49,"value":1518},"let",{"type":49,"value":408},{"type":43,"tag":73,"props":1521,"children":1523},{"className":1522},[],[1524],{"type":49,"value":1525},"const",{"type":49,"value":1527}," in test file (JS\u002FTS), ",{"type":43,"tag":73,"props":1529,"children":1531},{"className":1530},[],[1532],{"type":49,"value":1533},"var",{"type":49,"value":1535}," package globals (Go), class variables (Ruby), ",{"type":43,"tag":73,"props":1537,"children":1539},{"className":1538},[],[1540],{"type":49,"value":1541},"static mut",{"type":49,"value":408},{"type":43,"tag":73,"props":1544,"children":1546},{"className":1545},[],[1547],{"type":49,"value":1548},"lazy_static!",{"type":49,"value":408},{"type":43,"tag":73,"props":1551,"children":1553},{"className":1552},[],[1554],{"type":49,"value":1555},"OnceCell",{"type":49,"value":1257},{"type":43,"tag":73,"props":1558,"children":1560},{"className":1559},[],[1561],{"type":49,"value":1562},"$script:",{"type":49,"value":1564}," variables (PowerShell).",{"type":43,"tag":288,"props":1566,"children":1567},{},[1568,1576],{"type":43,"tag":315,"props":1569,"children":1570},{},[1571],{"type":43,"tag":65,"props":1572,"children":1573},{},[1574],{"type":49,"value":1575},"Over-mocking",{"type":43,"tag":315,"props":1577,"children":1578},{},[1579,1581,1587,1588,1594,1596,1602,1604,1610,1612,1618],{"type":49,"value":1580},"More mock setup lines than actual test logic. Verifying exact call sequences on mocks rather than outcomes. Mocking types the test owns. Per language: Moq\u002FNSubstitute\u002FFakeItEasy (.NET), ",{"type":43,"tag":73,"props":1582,"children":1584},{"className":1583},[],[1585],{"type":49,"value":1586},"unittest.mock",{"type":49,"value":431},{"type":43,"tag":73,"props":1589,"children":1591},{"className":1590},[],[1592],{"type":49,"value":1593},"pytest-mock",{"type":49,"value":1595}," (Python), Jest auto-mocks \u002F Sinon (JS\u002FTS), Mockito\u002FPowerMock (Java), gomock\u002Ftestify mock (Go), RSpec mocks\u002Fmocha (Ruby), ",{"type":43,"tag":73,"props":1597,"children":1599},{"className":1598},[],[1600],{"type":49,"value":1601},"mockall",{"type":49,"value":1603}," (Rust), MockK (Kotlin), ",{"type":43,"tag":73,"props":1605,"children":1607},{"className":1606},[],[1608],{"type":49,"value":1609},"Mock",{"type":49,"value":1611}," cmdlet (Pester), gmock (C++). For a deep mock audit in .NET, use ",{"type":43,"tag":73,"props":1613,"children":1615},{"className":1614},[],[1616],{"type":49,"value":1617},"exp-mock-usage-analysis",{"type":49,"value":1619},".",{"type":43,"tag":288,"props":1621,"children":1622},{},[1623,1631],{"type":43,"tag":315,"props":1624,"children":1625},{},[1626],{"type":43,"tag":65,"props":1627,"children":1628},{},[1629],{"type":49,"value":1630},"Implementation coupling",{"type":43,"tag":315,"props":1632,"children":1633},{},[1634,1636,1642,1643,1649,1651,1657,1659,1665,1667,1673,1675,1681],{"type":49,"value":1635},"Testing private methods via reflection (",{"type":43,"tag":73,"props":1637,"children":1639},{"className":1638},[],[1640],{"type":49,"value":1641},"MethodInfo.Invoke",{"type":49,"value":88},{"type":43,"tag":73,"props":1644,"children":1646},{"className":1645},[],[1647],{"type":49,"value":1648},"getattr",{"type":49,"value":1650}," in Python, ",{"type":43,"tag":73,"props":1652,"children":1654},{"className":1653},[],[1655],{"type":49,"value":1656},"(thing as any)",{"type":49,"value":1658}," in TS, ",{"type":43,"tag":73,"props":1660,"children":1662},{"className":1661},[],[1663],{"type":49,"value":1664},"Field.setAccessible(true)",{"type":49,"value":1666}," in Java, ",{"type":43,"tag":73,"props":1668,"children":1670},{"className":1669},[],[1671],{"type":49,"value":1672},"Object#send",{"type":49,"value":1674}," in Ruby, internal ",{"type":43,"tag":73,"props":1676,"children":1678},{"className":1677},[],[1679],{"type":49,"value":1680},"pub(crate)",{"type":49,"value":1682}," access in Rust). Asserting on internal state instead of observable behavior. Verifying exact method call counts on collaborators instead of business outcomes.",{"type":43,"tag":288,"props":1684,"children":1685},{},[1686,1694],{"type":43,"tag":315,"props":1687,"children":1688},{},[1689],{"type":43,"tag":65,"props":1690,"children":1691},{},[1692],{"type":49,"value":1693},"Broad exception assertions",{"type":43,"tag":315,"props":1695,"children":1696},{},[1697,1703,1705,1711,1712,1718,1720,1726,1728,1733,1735,1741,1743,1748,1749,1755,1756,1761,1762,1768,1769,1775,1777,1783],{"type":43,"tag":73,"props":1698,"children":1700},{"className":1699},[],[1701],{"type":49,"value":1702},"Assert.ThrowsException\u003CException>(...)",{"type":49,"value":1704}," (.NET) \u002F ",{"type":43,"tag":73,"props":1706,"children":1708},{"className":1707},[],[1709],{"type":49,"value":1710},"pytest.raises(Exception)",{"type":49,"value":431},{"type":43,"tag":73,"props":1713,"children":1715},{"className":1714},[],[1716],{"type":49,"value":1717},"expect(fn).toThrow(Error)",{"type":49,"value":1719}," without a message matcher \u002F ",{"type":43,"tag":73,"props":1721,"children":1723},{"className":1722},[],[1724],{"type":49,"value":1725},"assertThrows(Exception.class, ...)",{"type":49,"value":1727}," (Java) \u002F ",{"type":43,"tag":73,"props":1729,"children":1731},{"className":1730},[],[1732],{"type":49,"value":1049},{"type":49,"value":1734}," without checking the kind \u002F ",{"type":43,"tag":73,"props":1736,"children":1738},{"className":1737},[],[1739],{"type":49,"value":1740},"expect { ... }.to raise_error",{"type":49,"value":1742}," without class (RSpec) \u002F ",{"type":43,"tag":73,"props":1744,"children":1746},{"className":1745},[],[1747],{"type":49,"value":1056},{"type":49,"value":714},{"type":43,"tag":73,"props":1750,"children":1752},{"className":1751},[],[1753],{"type":49,"value":1754},"expected = \"...\"",{"type":49,"value":431},{"type":43,"tag":73,"props":1757,"children":1759},{"className":1758},[],[1760],{"type":49,"value":1063},{"type":49,"value":714},{"type":43,"tag":73,"props":1763,"children":1765},{"className":1764},[],[1766],{"type":49,"value":1767},"-ExpectedMessage",{"type":49,"value":431},{"type":43,"tag":73,"props":1770,"children":1772},{"className":1771},[],[1773],{"type":49,"value":1774},"EXPECT_ANY_THROW",{"type":49,"value":1776}," instead of ",{"type":43,"tag":73,"props":1778,"children":1780},{"className":1779},[],[1781],{"type":49,"value":1782},"EXPECT_THROW(stmt, SpecificType)",{"type":49,"value":1619},{"type":43,"tag":549,"props":1785,"children":1787},{"id":1786},"medium-maintainability-and-clarity-issues",[1788],{"type":49,"value":1789},"Medium -- Maintainability and clarity issues",{"type":43,"tag":280,"props":1791,"children":1792},{},[1793,1807],{"type":43,"tag":284,"props":1794,"children":1795},{},[1796],{"type":43,"tag":288,"props":1797,"children":1798},{},[1799,1803],{"type":43,"tag":292,"props":1800,"children":1801},{},[1802],{"type":49,"value":568},{"type":43,"tag":292,"props":1804,"children":1805},{},[1806],{"type":49,"value":573},{"type":43,"tag":308,"props":1808,"children":1809},{},[1810,1886,1924,2090,2106,2142],{"type":43,"tag":288,"props":1811,"children":1812},{},[1813,1821],{"type":43,"tag":315,"props":1814,"children":1815},{},[1816],{"type":43,"tag":65,"props":1817,"children":1818},{},[1819],{"type":49,"value":1820},"Poor naming",{"type":43,"tag":315,"props":1822,"children":1823},{},[1824,1826,1832,1833,1839,1840,1846,1848,1854,1855,1861,1862,1868,1870,1876,1878,1884],{"type":49,"value":1825},"Test names like ",{"type":43,"tag":73,"props":1827,"children":1829},{"className":1828},[],[1830],{"type":49,"value":1831},"Test1",{"type":49,"value":88},{"type":43,"tag":73,"props":1834,"children":1836},{"className":1835},[],[1837],{"type":49,"value":1838},"TestMethod",{"type":49,"value":88},{"type":43,"tag":73,"props":1841,"children":1843},{"className":1842},[],[1844],{"type":49,"value":1845},"test",{"type":49,"value":1847},", names that don't describe the scenario or expected outcome. Good naming differs by language convention — see the loaded language extension file (e.g., ",{"type":43,"tag":73,"props":1849,"children":1851},{"className":1850},[],[1852],{"type":49,"value":1853},"Add_NegativeNumber_ThrowsArgumentException",{"type":49,"value":423},{"type":43,"tag":73,"props":1856,"children":1858},{"className":1857},[],[1859],{"type":49,"value":1860},"test_add_negative_number_raises_value_error",{"type":49,"value":439},{"type":43,"tag":73,"props":1863,"children":1865},{"className":1864},[],[1866],{"type":49,"value":1867},"addNegativeNumber_throwsArgumentException",{"type":49,"value":1869}," for Java, ",{"type":43,"tag":73,"props":1871,"children":1873},{"className":1872},[],[1874],{"type":49,"value":1875},"'adds negative number throws'",{"type":49,"value":1877}," for Jest descriptions, ",{"type":43,"tag":73,"props":1879,"children":1881},{"className":1880},[],[1882],{"type":49,"value":1883},"TestAdd_NegativeNumber_ReturnsError",{"type":49,"value":1885}," for Go).",{"type":43,"tag":288,"props":1887,"children":1888},{},[1889,1897],{"type":43,"tag":315,"props":1890,"children":1891},{},[1892],{"type":43,"tag":65,"props":1893,"children":1894},{},[1895],{"type":49,"value":1896},"Magic values",{"type":43,"tag":315,"props":1898,"children":1899},{},[1900,1902,1908,1909,1915,1916,1922],{"type":49,"value":1901},"Unexplained numbers or strings in arrange\u002Fassert: ",{"type":43,"tag":73,"props":1903,"children":1905},{"className":1904},[],[1906],{"type":49,"value":1907},"Assert.AreEqual(42, result)",{"type":49,"value":431},{"type":43,"tag":73,"props":1910,"children":1912},{"className":1911},[],[1913],{"type":49,"value":1914},"assert result == 42",{"type":49,"value":431},{"type":43,"tag":73,"props":1917,"children":1919},{"className":1918},[],[1920],{"type":49,"value":1921},"expect(result).toBe(42)",{"type":49,"value":1923}," -- what does 42 mean?",{"type":43,"tag":288,"props":1925,"children":1926},{},[1927,1935],{"type":43,"tag":315,"props":1928,"children":1929},{},[1930],{"type":43,"tag":65,"props":1931,"children":1932},{},[1933],{"type":49,"value":1934},"Duplicate tests",{"type":43,"tag":315,"props":1936,"children":1937},{},[1938,1940,1946,1947,1953,1954,1960,1961,1967,1969,1975,1976,1982,1984,1990,1992,1998,2000,2006,2008,2014,2016,2022,2023,2028,2029,2035,2037,2043,2044,2050,2051,2057,2059,2065,2066,2072,2074,2080,2082,2088],{"type":49,"value":1939},"Three or more test methods with near-identical bodies that differ only in a single input value. Should be parametrized: ",{"type":43,"tag":73,"props":1941,"children":1943},{"className":1942},[],[1944],{"type":49,"value":1945},"[DataRow]",{"type":49,"value":408},{"type":43,"tag":73,"props":1948,"children":1950},{"className":1949},[],[1951],{"type":49,"value":1952},"[Theory]",{"type":49,"value":408},{"type":43,"tag":73,"props":1955,"children":1957},{"className":1956},[],[1958],{"type":49,"value":1959},"[TestCase]",{"type":49,"value":1202},{"type":43,"tag":73,"props":1962,"children":1964},{"className":1963},[],[1965],{"type":49,"value":1966},"@pytest.mark.parametrize",{"type":49,"value":1968}," (pytest), ",{"type":43,"tag":73,"props":1970,"children":1972},{"className":1971},[],[1973],{"type":49,"value":1974},"test.each",{"type":49,"value":431},{"type":43,"tag":73,"props":1977,"children":1979},{"className":1978},[],[1980],{"type":49,"value":1981},"it.each",{"type":49,"value":1983}," (Jest\u002FVitest), ",{"type":43,"tag":73,"props":1985,"children":1987},{"className":1986},[],[1988],{"type":49,"value":1989},"@ParameterizedTest",{"type":49,"value":1991}," + ",{"type":43,"tag":73,"props":1993,"children":1995},{"className":1994},[],[1996],{"type":49,"value":1997},"@ValueSource",{"type":49,"value":1999}," (JUnit 5), ",{"type":43,"tag":73,"props":2001,"children":2003},{"className":2002},[],[2004],{"type":49,"value":2005},"@DataProvider",{"type":49,"value":2007}," (TestNG), Go table-driven tests, ",{"type":43,"tag":73,"props":2009,"children":2011},{"className":2010},[],[2012],{"type":49,"value":2013},"where",{"type":49,"value":2015}," \u002F shared examples (RSpec), ",{"type":43,"tag":73,"props":2017,"children":2019},{"className":2018},[],[2020],{"type":49,"value":2021},"#[rstest]",{"type":49,"value":1257},{"type":43,"tag":73,"props":2024,"children":2026},{"className":2025},[],[2027],{"type":49,"value":1989},{"type":49,"value":1991},{"type":43,"tag":73,"props":2030,"children":2032},{"className":2031},[],[2033],{"type":49,"value":2034},"@MethodSource",{"type":49,"value":2036}," (Kotlin), ",{"type":43,"tag":73,"props":2038,"children":2040},{"className":2039},[],[2041],{"type":49,"value":2042},"-ForEach",{"type":49,"value":431},{"type":43,"tag":73,"props":2045,"children":2047},{"className":2046},[],[2048],{"type":49,"value":2049},"-TestCases",{"type":49,"value":1265},{"type":43,"tag":73,"props":2052,"children":2054},{"className":2053},[],[2055],{"type":49,"value":2056},"INSTANTIATE_TEST_SUITE_P",{"type":49,"value":2058}," (GoogleTest), ",{"type":43,"tag":73,"props":2060,"children":2062},{"className":2061},[],[2063],{"type":49,"value":2064},"SECTION",{"type":49,"value":431},{"type":43,"tag":73,"props":2067,"children":2069},{"className":2068},[],[2070],{"type":49,"value":2071},"GENERATE",{"type":49,"value":2073}," (Catch2), ",{"type":43,"tag":73,"props":2075,"children":2077},{"className":2076},[],[2078],{"type":49,"value":2079},"TEST_CASE_TEMPLATE",{"type":49,"value":2081}," (doctest). For a detailed duplication analysis in .NET, use ",{"type":43,"tag":73,"props":2083,"children":2085},{"className":2084},[],[2086],{"type":49,"value":2087},"exp-test-maintainability",{"type":49,"value":2089},". Note: Two tests covering distinct boundary conditions (e.g., zero vs. negative) are NOT duplicates -- separate tests for different edge cases provide clearer failure diagnostics and are a valid practice.",{"type":43,"tag":288,"props":2091,"children":2092},{},[2093,2101],{"type":43,"tag":315,"props":2094,"children":2095},{},[2096],{"type":43,"tag":65,"props":2097,"children":2098},{},[2099],{"type":49,"value":2100},"Giant tests",{"type":43,"tag":315,"props":2102,"children":2103},{},[2104],{"type":49,"value":2105},"Test methods exceeding ~30 lines or testing multiple behaviors at once. Hard to diagnose when they fail.",{"type":43,"tag":288,"props":2107,"children":2108},{},[2109,2117],{"type":43,"tag":315,"props":2110,"children":2111},{},[2112],{"type":43,"tag":65,"props":2113,"children":2114},{},[2115],{"type":49,"value":2116},"Assertion messages that repeat the assertion",{"type":43,"tag":315,"props":2118,"children":2119},{},[2120,2126,2127,2133,2134,2140],{"type":43,"tag":73,"props":2121,"children":2123},{"className":2122},[],[2124],{"type":49,"value":2125},"Assert.AreEqual(expected, actual, \"Expected and actual are not equal\")",{"type":49,"value":431},{"type":43,"tag":73,"props":2128,"children":2130},{"className":2129},[],[2131],{"type":49,"value":2132},"assert x == y, \"x is not equal to y\"",{"type":49,"value":431},{"type":43,"tag":73,"props":2135,"children":2137},{"className":2136},[],[2138],{"type":49,"value":2139},"assertEquals(x, y, \"values not equal\")",{"type":49,"value":2141}," add no information. Messages should describe the business meaning.",{"type":43,"tag":288,"props":2143,"children":2144},{},[2145,2153],{"type":43,"tag":315,"props":2146,"children":2147},{},[2148],{"type":43,"tag":65,"props":2149,"children":2150},{},[2151],{"type":49,"value":2152},"Missing AAA \u002F Given-When-Then separation",{"type":43,"tag":315,"props":2154,"children":2155},{},[2156],{"type":49,"value":2157},"Arrange\u002FAct\u002FAssert (or Given\u002FWhen\u002FThen for BDD frameworks like RSpec, Kotest behavior specs, Pester) phases are interleaved or indistinguishable.",{"type":43,"tag":549,"props":2159,"children":2161},{"id":2160},"low-style-and-hygiene",[2162],{"type":49,"value":2163},"Low -- Style and hygiene",{"type":43,"tag":280,"props":2165,"children":2166},{},[2167,2181],{"type":43,"tag":284,"props":2168,"children":2169},{},[2170],{"type":43,"tag":288,"props":2171,"children":2172},{},[2173,2177],{"type":43,"tag":292,"props":2174,"children":2175},{},[2176],{"type":49,"value":568},{"type":43,"tag":292,"props":2178,"children":2179},{},[2180],{"type":49,"value":573},{"type":43,"tag":308,"props":2182,"children":2183},{},[2184,2287,2386,2473],{"type":43,"tag":288,"props":2185,"children":2186},{},[2187,2195],{"type":43,"tag":315,"props":2188,"children":2189},{},[2190],{"type":43,"tag":65,"props":2191,"children":2192},{},[2193],{"type":49,"value":2194},"Unused test infrastructure",{"type":43,"tag":315,"props":2196,"children":2197},{},[2198,2200,2205,2206,2212,2213,2219,2220,2225,2226,2232,2233,2239,2240,2245,2246,2252,2253,2258,2259,2265,2266,2271,2272,2278,2279,2285],{"type":49,"value":2199},"Setup\u002Fteardown hooks that do nothing — ",{"type":43,"tag":73,"props":2201,"children":2203},{"className":2202},[],[2204],{"type":49,"value":1467},{"type":49,"value":408},{"type":43,"tag":73,"props":2207,"children":2209},{"className":2208},[],[2210],{"type":49,"value":2211},"[SetUp]",{"type":49,"value":408},{"type":43,"tag":73,"props":2214,"children":2216},{"className":2215},[],[2217],{"type":49,"value":2218},"[BeforeEach]",{"type":49,"value":88},{"type":43,"tag":73,"props":2221,"children":2223},{"className":2222},[],[2224],{"type":49,"value":1474},{"type":49,"value":408},{"type":43,"tag":73,"props":2227,"children":2229},{"className":2228},[],[2230],{"type":49,"value":2231},"@BeforeEach",{"type":49,"value":408},{"type":43,"tag":73,"props":2234,"children":2236},{"className":2235},[],[2237],{"type":49,"value":2238},"@BeforeAll",{"type":49,"value":88},{"type":43,"tag":73,"props":2241,"children":2243},{"className":2242},[],[2244],{"type":49,"value":1481},{"type":49,"value":408},{"type":43,"tag":73,"props":2247,"children":2249},{"className":2248},[],[2250],{"type":49,"value":2251},"beforeAll",{"type":49,"value":88},{"type":43,"tag":73,"props":2254,"children":2256},{"className":2255},[],[2257],{"type":49,"value":1488},{"type":49,"value":408},{"type":43,"tag":73,"props":2260,"children":2262},{"className":2261},[],[2263],{"type":49,"value":2264},"before(:all)",{"type":49,"value":88},{"type":43,"tag":73,"props":2267,"children":2269},{"className":2268},[],[2270],{"type":49,"value":1495},{"type":49,"value":408},{"type":43,"tag":73,"props":2273,"children":2275},{"className":2274},[],[2276],{"type":49,"value":2277},"BeforeAll",{"type":49,"value":1265},{"type":43,"tag":73,"props":2280,"children":2282},{"className":2281},[],[2283],{"type":49,"value":2284},"setUpWithError",{"type":49,"value":2286}," (XCTest) — and test helper methods that are never called.",{"type":43,"tag":288,"props":2288,"children":2289},{},[2290,2298],{"type":43,"tag":315,"props":2291,"children":2292},{},[2293],{"type":43,"tag":65,"props":2294,"children":2295},{},[2296],{"type":49,"value":2297},"Unmanaged resources",{"type":43,"tag":315,"props":2299,"children":2300},{},[2301,2303,2309,2310,2316,2317,2323,2325,2331,2333,2339,2340,2346,2347,2353,2355,2361,2363,2369,2370,2376,2378,2384],{"type":49,"value":2302},"Test creates disposable\u002Fcloseable resources without cleanup: ",{"type":43,"tag":73,"props":2304,"children":2306},{"className":2305},[],[2307],{"type":49,"value":2308},"HttpClient",{"type":49,"value":408},{"type":43,"tag":73,"props":2311,"children":2313},{"className":2312},[],[2314],{"type":49,"value":2315},"Stream",{"type":49,"value":714},{"type":43,"tag":73,"props":2318,"children":2320},{"className":2319},[],[2321],{"type":49,"value":2322},"using",{"type":49,"value":2324}," (.NET), file\u002Fconnection without ",{"type":43,"tag":73,"props":2326,"children":2328},{"className":2327},[],[2329],{"type":49,"value":2330},"with",{"type":49,"value":2332}," block or ",{"type":43,"tag":73,"props":2334,"children":2336},{"className":2335},[],[2337],{"type":49,"value":2338},"try\u002Ffinally",{"type":49,"value":1210},{"type":43,"tag":73,"props":2341,"children":2343},{"className":2342},[],[2344],{"type":49,"value":2345},"FileInputStream",{"type":49,"value":714},{"type":43,"tag":73,"props":2348,"children":2350},{"className":2349},[],[2351],{"type":49,"value":2352},"try-with-resources",{"type":49,"value":2354}," (Java), ",{"type":43,"tag":73,"props":2356,"children":2358},{"className":2357},[],[2359],{"type":49,"value":2360},"defer file.Close()",{"type":49,"value":2362}," missing (Go), connection without ",{"type":43,"tag":73,"props":2364,"children":2366},{"className":2365},[],[2367],{"type":49,"value":2368},"ensure",{"type":49,"value":1422},{"type":43,"tag":73,"props":2371,"children":2373},{"className":2372},[],[2374],{"type":49,"value":2375},"Drop",{"type":49,"value":2377}," not relied on \u002F forgotten ",{"type":43,"tag":73,"props":2379,"children":2381},{"className":2380},[],[2382],{"type":49,"value":2383},"close",{"type":49,"value":2385}," (Rust), missing teardown for temp files \u002F DBs in any language.",{"type":43,"tag":288,"props":2387,"children":2388},{},[2389,2397],{"type":43,"tag":315,"props":2390,"children":2391},{},[2392],{"type":43,"tag":65,"props":2393,"children":2394},{},[2395],{"type":49,"value":2396},"Print debugging",{"type":43,"tag":315,"props":2398,"children":2399},{},[2400,2402,2408,2409,2415,2416,2422,2423,2429,2430,2436,2437,2443,2444,2450,2451,2457,2458,2464,2465,2471],{"type":49,"value":2401},"Leftover ",{"type":43,"tag":73,"props":2403,"children":2405},{"className":2404},[],[2406],{"type":49,"value":2407},"Console.WriteLine",{"type":49,"value":431},{"type":43,"tag":73,"props":2410,"children":2412},{"className":2411},[],[2413],{"type":49,"value":2414},"Debug.WriteLine",{"type":49,"value":431},{"type":43,"tag":73,"props":2417,"children":2419},{"className":2418},[],[2420],{"type":49,"value":2421},"print()",{"type":49,"value":431},{"type":43,"tag":73,"props":2424,"children":2426},{"className":2425},[],[2427],{"type":49,"value":2428},"console.log",{"type":49,"value":431},{"type":43,"tag":73,"props":2431,"children":2433},{"className":2432},[],[2434],{"type":49,"value":2435},"System.out.println",{"type":49,"value":431},{"type":43,"tag":73,"props":2438,"children":2440},{"className":2439},[],[2441],{"type":49,"value":2442},"fmt.Println",{"type":49,"value":431},{"type":43,"tag":73,"props":2445,"children":2447},{"className":2446},[],[2448],{"type":49,"value":2449},"puts",{"type":49,"value":431},{"type":43,"tag":73,"props":2452,"children":2454},{"className":2453},[],[2455],{"type":49,"value":2456},"dbg!",{"type":49,"value":431},{"type":43,"tag":73,"props":2459,"children":2461},{"className":2460},[],[2462],{"type":49,"value":2463},"Write-Host",{"type":49,"value":431},{"type":43,"tag":73,"props":2466,"children":2468},{"className":2467},[],[2469],{"type":49,"value":2470},"std::cout",{"type":49,"value":2472}," statements used during test development.",{"type":43,"tag":288,"props":2474,"children":2475},{},[2476,2484],{"type":43,"tag":315,"props":2477,"children":2478},{},[2479],{"type":43,"tag":65,"props":2480,"children":2481},{},[2482],{"type":49,"value":2483},"Inconsistent naming convention",{"type":43,"tag":315,"props":2485,"children":2486},{},[2487,2489,2495,2497,2503],{"type":49,"value":2488},"Mix of naming styles in the same test class\u002Fmodule\u002Ffile (e.g., some use ",{"type":43,"tag":73,"props":2490,"children":2492},{"className":2491},[],[2493],{"type":49,"value":2494},"Method_Scenario_Expected",{"type":49,"value":2496},", others use ",{"type":43,"tag":73,"props":2498,"children":2500},{"className":2499},[],[2501],{"type":49,"value":2502},"ShouldDoSomething",{"type":49,"value":2504},").",{"type":43,"tag":372,"props":2506,"children":2508},{"id":2507},"step-4-calibrate-severity-honestly",[2509],{"type":49,"value":2510},"Step 4: Calibrate severity honestly",{"type":43,"tag":52,"props":2512,"children":2513},{},[2514],{"type":49,"value":2515},"Before reporting, re-check each finding against these severity rules:",{"type":43,"tag":119,"props":2517,"children":2518},{},[2519,2529,2558,2568],{"type":43,"tag":123,"props":2520,"children":2521},{},[2522,2527],{"type":43,"tag":65,"props":2523,"children":2524},{},[2525],{"type":49,"value":2526},"Critical\u002FHigh",{"type":49,"value":2528},": Only for issues that cause tests to give false confidence or be unreliable. A test that always passes regardless of correctness is Critical. Flaky shared state is High. Missing-await on async assertions is Critical (silent pass).",{"type":43,"tag":123,"props":2530,"children":2531},{},[2532,2537,2539,2544,2545,2550,2551,2557],{"type":43,"tag":65,"props":2533,"children":2534},{},[2535],{"type":49,"value":2536},"Medium",{"type":49,"value":2538},": Only for issues that actively harm maintainability -- 5+ nearly-identical tests, truly meaningless names like ",{"type":43,"tag":73,"props":2540,"children":2542},{"className":2541},[],[2543],{"type":49,"value":1831},{"type":49,"value":431},{"type":43,"tag":73,"props":2546,"children":2548},{"className":2547},[],[2549],{"type":49,"value":1845},{"type":49,"value":431},{"type":43,"tag":73,"props":2552,"children":2554},{"className":2553},[],[2555],{"type":49,"value":2556},"it1",{"type":49,"value":1619},{"type":43,"tag":123,"props":2559,"children":2560},{},[2561,2566],{"type":43,"tag":65,"props":2562,"children":2563},{},[2564],{"type":49,"value":2565},"Low",{"type":49,"value":2567},": Cosmetic naming mismatches, minor style preferences, assertion messages that could be better. When in doubt, rate Low.",{"type":43,"tag":123,"props":2569,"children":2570},{},[2571,2576,2578],{"type":43,"tag":65,"props":2572,"children":2573},{},[2574],{"type":49,"value":2575},"Not an issue",{"type":49,"value":2577}," (per-language nuance):\n",{"type":43,"tag":119,"props":2579,"children":2580},{},[2581,2615,2632,2645,2650,2675],{"type":43,"tag":123,"props":2582,"children":2583},{},[2584,2586,2591,2593,2599,2600,2606,2608,2613],{"type":49,"value":2585},"Go and Rust ",{"type":43,"tag":65,"props":2587,"children":2588},{},[2589],{"type":49,"value":2590},"table-driven loops",{"type":49,"value":2592}," with sub-tests (",{"type":43,"tag":73,"props":2594,"children":2596},{"className":2595},[],[2597],{"type":49,"value":2598},"t.Run",{"type":49,"value":431},{"type":43,"tag":73,"props":2601,"children":2603},{"className":2602},[],[2604],{"type":49,"value":2605},"for case in cases { ... }",{"type":49,"value":2607},") are ",{"type":43,"tag":821,"props":2609,"children":2610},{},[2611],{"type":49,"value":2612},"idiomatic",{"type":49,"value":2614},", not \"Conditional Test Logic\". Do NOT flag.",{"type":43,"tag":123,"props":2616,"children":2617},{},[2618,2620,2630],{"type":49,"value":2619},"pytest ",{"type":43,"tag":65,"props":2621,"children":2622},{},[2623,2625],{"type":49,"value":2624},"bare ",{"type":43,"tag":73,"props":2626,"children":2628},{"className":2627},[],[2629],{"type":49,"value":606},{"type":49,"value":2631}," is the canonical assertion form, not a missing assertion library. Do NOT flag.",{"type":43,"tag":123,"props":2633,"children":2634},{},[2635,2637,2643],{"type":49,"value":2636},"Go tests use ",{"type":43,"tag":73,"props":2638,"children":2640},{"className":2639},[],[2641],{"type":49,"value":2642},"if got != want { t.Errorf(...) }",{"type":49,"value":2644}," as canonical equality. Do NOT flag as ad-hoc.",{"type":43,"tag":123,"props":2646,"children":2647},{},[2648],{"type":49,"value":2649},"Separate tests for distinct boundary conditions (zero vs. negative vs. null). Do NOT flag as duplicates.",{"type":43,"tag":123,"props":2651,"children":2652},{},[2653,2655,2660,2661,2666,2668,2673],{"type":49,"value":2654},"Explicit per-test setup instead of ",{"type":43,"tag":73,"props":2656,"children":2658},{"className":2657},[],[2659],{"type":49,"value":1467},{"type":49,"value":431},{"type":43,"tag":73,"props":2662,"children":2664},{"className":2663},[],[2665],{"type":49,"value":1481},{"type":49,"value":2667}," (this ",{"type":43,"tag":821,"props":2669,"children":2670},{},[2671],{"type":49,"value":2672},"improves",{"type":49,"value":2674}," isolation).",{"type":43,"tag":123,"props":2676,"children":2677},{},[2678],{"type":49,"value":2679},"Tests that are short and clear but could theoretically be consolidated.",{"type":43,"tag":52,"props":2681,"children":2682},{},[2683],{"type":49,"value":2684},"IMPORTANT: If the tests are well-written, say so clearly up front. Do not inflate severity to justify the review. A review that finds zero Critical\u002FHigh issues and only minor Low suggestions is a valid and valuable outcome. Lead with what the tests do well.",{"type":43,"tag":372,"props":2686,"children":2688},{"id":2687},"step-5-report-findings",[2689],{"type":49,"value":2690},"Step 5: Report findings",{"type":43,"tag":52,"props":2692,"children":2693},{},[2694,2699],{"type":43,"tag":65,"props":2695,"children":2696},{},[2697],{"type":49,"value":2698},"Depth bar — a tidy report that is shallower than an unassisted review is a failure.",{"type":49,"value":2700}," Before writing, satisfy all four:",{"type":43,"tag":2702,"props":2703,"children":2704},"ol",{},[2705,2723,2748,2758],{"type":43,"tag":123,"props":2706,"children":2707},{},[2708,2713,2715,2721],{"type":43,"tag":65,"props":2709,"children":2710},{},[2711],{"type":49,"value":2712},"Account for every test in scope.",{"type":49,"value":2714}," Walk the full list of test methods and fields; a finding table that silently skips tests (or fixtures like an unused ",{"type":43,"tag":73,"props":2716,"children":2718},{"className":2717},[],[2719],{"type":49,"value":2720},"static HttpClient",{"type":49,"value":2722}," field) is incomplete. State the number of tests reviewed.",{"type":43,"tag":123,"props":2724,"children":2725},{},[2726,2731,2733,2738,2740,2746],{"type":43,"tag":65,"props":2727,"children":2728},{},[2729],{"type":49,"value":2730},"Make every Critical\u002FHigh fix complete and specific.",{"type":49,"value":2732}," Give the replacement assertion with the ",{"type":43,"tag":821,"props":2734,"children":2735},{},[2736],{"type":49,"value":2737},"exact expected value",{"type":49,"value":2739}," (the computed discount, the exact CSV line, the full expected object), not a ",{"type":43,"tag":73,"props":2741,"children":2743},{"className":2742},[],[2744],{"type":49,"value":2745},"\u002F\u002F assert something here",{"type":49,"value":2747}," placeholder.",{"type":43,"tag":123,"props":2749,"children":2750},{},[2751,2756],{"type":43,"tag":65,"props":2752,"children":2753},{},[2754],{"type":49,"value":2755},"Name the adjacent gaps the tests should also cover",{"type":49,"value":2757}," — untested error paths, boundary values, and round-trip\u002Fculture-sensitivity risks in the same class. These are part of \"what's wrong with my tests\", and omitting them is the most common way this review loses to an unassisted one.",{"type":43,"tag":123,"props":2759,"children":2760},{},[2761,2766],{"type":43,"tag":65,"props":2762,"children":2763},{},[2764],{"type":49,"value":2765},"Keep the report internally consistent.",{"type":49,"value":2767}," Summary counts must equal the enumerated findings. Publish a settled conclusion: do all reconsidering before you write, and never leave \"wait, that's wrong\" \u002F \"this should fail but doesn't\" reasoning in the output.",{"type":43,"tag":52,"props":2769,"children":2770},{},[2771],{"type":49,"value":2772},"Present findings in this structure:",{"type":43,"tag":2702,"props":2774,"children":2775},{},[2776,2786,2819,2829],{"type":43,"tag":123,"props":2777,"children":2778},{},[2779,2784],{"type":43,"tag":65,"props":2780,"children":2781},{},[2782],{"type":49,"value":2783},"Summary",{"type":49,"value":2785}," -- Total issues found, broken down by severity (Critical \u002F High \u002F Medium \u002F Low). If tests are well-written, lead with that assessment.",{"type":43,"tag":123,"props":2787,"children":2788},{},[2789,2794,2796],{"type":43,"tag":65,"props":2790,"children":2791},{},[2792],{"type":49,"value":2793},"Critical and High findings",{"type":49,"value":2795}," -- List each with:\n",{"type":43,"tag":119,"props":2797,"children":2798},{},[2799,2804,2809,2814],{"type":43,"tag":123,"props":2800,"children":2801},{},[2802],{"type":49,"value":2803},"The anti-pattern name",{"type":43,"tag":123,"props":2805,"children":2806},{},[2807],{"type":49,"value":2808},"The specific location (file, method name, line)",{"type":43,"tag":123,"props":2810,"children":2811},{},[2812],{"type":49,"value":2813},"A brief explanation of why it's a problem",{"type":43,"tag":123,"props":2815,"children":2816},{},[2817],{"type":49,"value":2818},"A concrete fix (show before\u002Fafter code when helpful)",{"type":43,"tag":123,"props":2820,"children":2821},{},[2822,2827],{"type":43,"tag":65,"props":2823,"children":2824},{},[2825],{"type":49,"value":2826},"Medium and Low findings",{"type":49,"value":2828}," -- Summarize in a table unless the user wants full detail",{"type":43,"tag":123,"props":2830,"children":2831},{},[2832,2837],{"type":43,"tag":65,"props":2833,"children":2834},{},[2835],{"type":49,"value":2836},"Positive observations",{"type":49,"value":2838}," -- Call out things the tests do well (sealed class, specific exception types, data-driven tests, clear AAA structure, proper use of fakes, good naming). Don't only report negatives.",{"type":43,"tag":372,"props":2840,"children":2842},{"id":2841},"step-6-prioritize-recommendations",[2843],{"type":49,"value":2844},"Step 6: Prioritize recommendations",{"type":43,"tag":52,"props":2846,"children":2847},{},[2848],{"type":49,"value":2849},"If there are many findings, recommend which to fix first:",{"type":43,"tag":2702,"props":2851,"children":2852},{},[2853,2863,2873],{"type":43,"tag":123,"props":2854,"children":2855},{},[2856,2861],{"type":43,"tag":65,"props":2857,"children":2858},{},[2859],{"type":49,"value":2860},"Critical",{"type":49,"value":2862}," -- Fix immediately, these tests may be giving false confidence",{"type":43,"tag":123,"props":2864,"children":2865},{},[2866,2871],{"type":43,"tag":65,"props":2867,"children":2868},{},[2869],{"type":49,"value":2870},"High",{"type":49,"value":2872}," -- Fix soon, these cause flakiness or maintenance burden",{"type":43,"tag":123,"props":2874,"children":2875},{},[2876,2881],{"type":43,"tag":65,"props":2877,"children":2878},{},[2879],{"type":49,"value":2880},"Medium\u002FLow",{"type":49,"value":2882}," -- Fix opportunistically during related edits",{"type":43,"tag":112,"props":2884,"children":2886},{"id":2885},"validation",[2887],{"type":49,"value":2888},"Validation",{"type":43,"tag":119,"props":2890,"children":2893},{"className":2891},[2892],"contains-task-list",[2894,2907,2916,2925,2934,2943,2952,2961],{"type":43,"tag":123,"props":2895,"children":2898},{"className":2896},[2897],"task-list-item",[2899,2905],{"type":43,"tag":2900,"props":2901,"children":2904},"input",{"disabled":2902,"type":2903},true,"checkbox",[],{"type":49,"value":2906}," Every test method in scope is accounted for (reviewed count stated; none silently skipped)",{"type":43,"tag":123,"props":2908,"children":2910},{"className":2909},[2897],[2911,2914],{"type":43,"tag":2900,"props":2912,"children":2913},{"disabled":2902,"type":2903},[],{"type":49,"value":2915}," Every finding includes a specific location (not just a general warning)",{"type":43,"tag":123,"props":2917,"children":2919},{"className":2918},[2897],[2920,2923],{"type":43,"tag":2900,"props":2921,"children":2922},{"disabled":2902,"type":2903},[],{"type":49,"value":2924}," Every Critical\u002FHigh finding includes a concrete fix with exact expected values",{"type":43,"tag":123,"props":2926,"children":2928},{"className":2927},[2897],[2929,2932],{"type":43,"tag":2900,"props":2930,"children":2931},{"disabled":2902,"type":2903},[],{"type":49,"value":2933}," Adjacent untested error paths and boundary values are called out",{"type":43,"tag":123,"props":2935,"children":2937},{"className":2936},[2897],[2938,2941],{"type":43,"tag":2900,"props":2939,"children":2940},{"disabled":2902,"type":2903},[],{"type":49,"value":2942}," Summary counts match the enumerated findings",{"type":43,"tag":123,"props":2944,"children":2946},{"className":2945},[2897],[2947,2950],{"type":43,"tag":2900,"props":2948,"children":2949},{"disabled":2902,"type":2903},[],{"type":49,"value":2951}," Report covers all categories (assertions, isolation, naming, structure)",{"type":43,"tag":123,"props":2953,"children":2955},{"className":2954},[2897],[2956,2959],{"type":43,"tag":2900,"props":2957,"children":2958},{"disabled":2902,"type":2903},[],{"type":49,"value":2960}," Positive observations are included alongside problems",{"type":43,"tag":123,"props":2962,"children":2964},{"className":2963},[2897],[2965,2968],{"type":43,"tag":2900,"props":2966,"children":2967},{"disabled":2902,"type":2903},[],{"type":49,"value":2969}," Recommendations are prioritized by severity",{"type":43,"tag":112,"props":2971,"children":2973},{"id":2972},"common-pitfalls",[2974],{"type":49,"value":2975},"Common Pitfalls",{"type":43,"tag":280,"props":2977,"children":2978},{},[2979,2995],{"type":43,"tag":284,"props":2980,"children":2981},{},[2982],{"type":43,"tag":288,"props":2983,"children":2984},{},[2985,2990],{"type":43,"tag":292,"props":2986,"children":2987},{},[2988],{"type":49,"value":2989},"Pitfall",{"type":43,"tag":292,"props":2991,"children":2992},{},[2993],{"type":49,"value":2994},"Solution",{"type":43,"tag":308,"props":2996,"children":2997},{},[2998,3011,3024,3056,3069,3082,3111,3124,3137,3150,3163],{"type":43,"tag":288,"props":2999,"children":3000},{},[3001,3006],{"type":43,"tag":315,"props":3002,"children":3003},{},[3004],{"type":49,"value":3005},"Reporting style issues as critical",{"type":43,"tag":315,"props":3007,"children":3008},{},[3009],{"type":49,"value":3010},"Naming and formatting are Medium\u002FLow, never Critical",{"type":43,"tag":288,"props":3012,"children":3013},{},[3014,3019],{"type":43,"tag":315,"props":3015,"children":3016},{},[3017],{"type":49,"value":3018},"Suggesting rewrites instead of targeted fixes",{"type":43,"tag":315,"props":3020,"children":3021},{},[3022],{"type":49,"value":3023},"Show minimal diffs -- change the assertion, not the whole test",{"type":43,"tag":288,"props":3025,"children":3026},{},[3027,3032],{"type":43,"tag":315,"props":3028,"children":3029},{},[3030],{"type":49,"value":3031},"Flagging intentional design choices",{"type":43,"tag":315,"props":3033,"children":3034},{},[3035,3037,3042,3043,3048,3049,3054],{"type":49,"value":3036},"If ",{"type":43,"tag":73,"props":3038,"children":3040},{"className":3039},[],[3041],{"type":49,"value":1193},{"type":49,"value":431},{"type":43,"tag":73,"props":3044,"children":3046},{"className":3045},[],[3047],{"type":49,"value":1208},{"type":49,"value":431},{"type":43,"tag":73,"props":3050,"children":3052},{"className":3051},[],[3053],{"type":49,"value":1239},{"type":49,"value":3055}," is in an integration test testing actual timing, that's not an anti-pattern. Consider context.",{"type":43,"tag":288,"props":3057,"children":3058},{},[3059,3064],{"type":43,"tag":315,"props":3060,"children":3061},{},[3062],{"type":49,"value":3063},"Inventing false positives on clean code",{"type":43,"tag":315,"props":3065,"children":3066},{},[3067],{"type":49,"value":3068},"If tests follow best practices, say so. A review finding \"0 Critical, 0 High, 1 Low\" is perfectly valid. Don't inflate findings to justify the review.",{"type":43,"tag":288,"props":3070,"children":3071},{},[3072,3077],{"type":43,"tag":315,"props":3073,"children":3074},{},[3075],{"type":49,"value":3076},"Flagging separate boundary tests as duplicates",{"type":43,"tag":315,"props":3078,"children":3079},{},[3080],{"type":49,"value":3081},"Two tests for zero and negative inputs test different edge cases. Only flag as duplicates when 3+ tests have truly identical bodies differing by a single value.",{"type":43,"tag":288,"props":3083,"children":3084},{},[3085,3090],{"type":43,"tag":315,"props":3086,"children":3087},{},[3088],{"type":49,"value":3089},"Rating cosmetic issues as Medium",{"type":43,"tag":315,"props":3091,"children":3092},{},[3093,3095,3101,3103,3109],{"type":49,"value":3094},"Naming mismatches (e.g., method name says ",{"type":43,"tag":73,"props":3096,"children":3098},{"className":3097},[],[3099],{"type":49,"value":3100},"ArgumentException",{"type":49,"value":3102}," but asserts ",{"type":43,"tag":73,"props":3104,"children":3106},{"className":3105},[],[3107],{"type":49,"value":3108},"ArgumentOutOfRangeException",{"type":49,"value":3110},") are Low, not Medium -- the test still works correctly.",{"type":43,"tag":288,"props":3112,"children":3113},{},[3114,3119],{"type":43,"tag":315,"props":3115,"children":3116},{},[3117],{"type":49,"value":3118},"Ignoring the test framework",{"type":43,"tag":315,"props":3120,"children":3121},{},[3122],{"type":49,"value":3123},"Use the terminology of the framework you loaded from the language extension; don't describe a pytest suite in MSTest terms.",{"type":43,"tag":288,"props":3125,"children":3126},{},[3127,3132],{"type":43,"tag":315,"props":3128,"children":3129},{},[3130],{"type":49,"value":3131},"Missing the forest for the trees",{"type":43,"tag":315,"props":3133,"children":3134},{},[3135],{"type":49,"value":3136},"If 80% of tests have no assertions, lead with that systemic issue rather than listing every instance",{"type":43,"tag":288,"props":3138,"children":3139},{},[3140,3145],{"type":43,"tag":315,"props":3141,"children":3142},{},[3143],{"type":49,"value":3144},"Trading depth for tidiness",{"type":43,"tag":315,"props":3146,"children":3147},{},[3148],{"type":49,"value":3149},"A severity table and positive observations do not substitute for coverage of every test, exact expected values in fixes, and the adjacent error-path\u002Fboundary gaps",{"type":43,"tag":288,"props":3151,"children":3152},{},[3153,3158],{"type":43,"tag":315,"props":3154,"children":3155},{},[3156],{"type":49,"value":3157},"Contradicting yourself in the report",{"type":43,"tag":315,"props":3159,"children":3160},{},[3161],{"type":49,"value":3162},"Reason first, then write one settled verdict per finding — never emit \"wait, that's wrong\" \u002F \"should fail but doesn't\" reconsiderations",{"type":43,"tag":288,"props":3164,"children":3165},{},[3166,3171],{"type":43,"tag":315,"props":3167,"children":3168},{},[3169],{"type":49,"value":3170},"Counts that don't add up",{"type":43,"tag":315,"props":3172,"children":3173},{},[3174],{"type":49,"value":3175},"The summary's per-severity totals must match the findings you listed",{"items":3177,"total":3280},[3178,3191,3206,3224,3236,3256,3266],{"slug":3179,"name":3179,"fn":3180,"description":3181,"org":3182,"tags":3183,"stars":25,"repoUrl":26,"updatedAt":3190},"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},[3184,3185,3186,3187],{"name":13,"slug":14,"type":15},{"name":17,"slug":18,"type":15},{"name":23,"slug":24,"type":15},{"name":3188,"slug":3189,"type":15},"Performance","performance","2026-07-12T08:23:25.400375",{"slug":3192,"name":3192,"fn":3193,"description":3194,"org":3195,"tags":3196,"stars":25,"repoUrl":26,"updatedAt":3205},"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},[3197,3198,3201,3202],{"name":13,"slug":14,"type":15},{"name":3199,"slug":3200,"type":15},"Android","android",{"name":23,"slug":24,"type":15},{"name":3203,"slug":3204,"type":15},"Microsoft","microsoft","2026-07-12T08:23:21.595572",{"slug":3207,"name":3207,"fn":3208,"description":3209,"org":3210,"tags":3211,"stars":25,"repoUrl":26,"updatedAt":3223},"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},[3212,3213,3214,3217,3220],{"name":13,"slug":14,"type":15},{"name":23,"slug":24,"type":15},{"name":3215,"slug":3216,"type":15},"iOS","ios",{"name":3218,"slug":3219,"type":15},"macOS","macos",{"name":3221,"slug":3222,"type":15},"Observability","observability","2026-07-12T08:23:20.369986",{"slug":3225,"name":3225,"fn":3226,"description":3227,"org":3228,"tags":3229,"stars":25,"repoUrl":26,"updatedAt":3235},"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},[3230,3231,3234],{"name":17,"slug":18,"type":15},{"name":3232,"slug":3233,"type":15},"QA","qa",{"name":20,"slug":21,"type":15},"2026-07-12T08:23:51.277743",{"slug":3237,"name":3237,"fn":3238,"description":3239,"org":3240,"tags":3241,"stars":25,"repoUrl":26,"updatedAt":3255},"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},[3242,3243,3246,3249,3252],{"name":13,"slug":14,"type":15},{"name":3244,"slug":3245,"type":15},"Blazor","blazor",{"name":3247,"slug":3248,"type":15},"C#","csharp",{"name":3250,"slug":3251,"type":15},"UI Components","ui-components",{"name":3253,"slug":3254,"type":15},"Web Development","web-development","2026-07-15T06:03:29.216359",{"slug":3257,"name":3257,"fn":3258,"description":3259,"org":3260,"tags":3261,"stars":25,"repoUrl":26,"updatedAt":3265},"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},[3262,3263,3264],{"name":17,"slug":18,"type":15},{"name":23,"slug":24,"type":15},{"name":3203,"slug":3204,"type":15},"2026-07-12T08:21:34.637923",{"slug":3267,"name":3267,"fn":3268,"description":3269,"org":3270,"tags":3271,"stars":25,"repoUrl":26,"updatedAt":3279},"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},[3272,3275,3276],{"name":3273,"slug":3274,"type":15},"Build","build",{"name":23,"slug":24,"type":15},{"name":3277,"slug":3278,"type":15},"Engineering","engineering","2026-07-19T05:38:19.340791",96,{"items":3282,"total":3387},[3283,3295,3302,3309,3317,3323,3331,3337,3343,3353,3366,3377],{"slug":3284,"name":3284,"fn":3285,"description":3286,"org":3287,"tags":3288,"stars":3292,"repoUrl":3293,"updatedAt":3294},"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},[3289,3290,3291],{"name":13,"slug":14,"type":15},{"name":3277,"slug":3278,"type":15},{"name":3188,"slug":3189,"type":15},5535,"https:\u002F\u002Fgithub.com\u002Fdotnet\u002Fmsbuild","2026-07-22T05:37:33.965588",{"slug":3179,"name":3179,"fn":3180,"description":3181,"org":3296,"tags":3297,"stars":25,"repoUrl":26,"updatedAt":3190},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3298,3299,3300,3301],{"name":13,"slug":14,"type":15},{"name":17,"slug":18,"type":15},{"name":23,"slug":24,"type":15},{"name":3188,"slug":3189,"type":15},{"slug":3192,"name":3192,"fn":3193,"description":3194,"org":3303,"tags":3304,"stars":25,"repoUrl":26,"updatedAt":3205},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3305,3306,3307,3308],{"name":13,"slug":14,"type":15},{"name":3199,"slug":3200,"type":15},{"name":23,"slug":24,"type":15},{"name":3203,"slug":3204,"type":15},{"slug":3207,"name":3207,"fn":3208,"description":3209,"org":3310,"tags":3311,"stars":25,"repoUrl":26,"updatedAt":3223},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3312,3313,3314,3315,3316],{"name":13,"slug":14,"type":15},{"name":23,"slug":24,"type":15},{"name":3215,"slug":3216,"type":15},{"name":3218,"slug":3219,"type":15},{"name":3221,"slug":3222,"type":15},{"slug":3225,"name":3225,"fn":3226,"description":3227,"org":3318,"tags":3319,"stars":25,"repoUrl":26,"updatedAt":3235},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3320,3321,3322],{"name":17,"slug":18,"type":15},{"name":3232,"slug":3233,"type":15},{"name":20,"slug":21,"type":15},{"slug":3237,"name":3237,"fn":3238,"description":3239,"org":3324,"tags":3325,"stars":25,"repoUrl":26,"updatedAt":3255},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3326,3327,3328,3329,3330],{"name":13,"slug":14,"type":15},{"name":3244,"slug":3245,"type":15},{"name":3247,"slug":3248,"type":15},{"name":3250,"slug":3251,"type":15},{"name":3253,"slug":3254,"type":15},{"slug":3257,"name":3257,"fn":3258,"description":3259,"org":3332,"tags":3333,"stars":25,"repoUrl":26,"updatedAt":3265},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3334,3335,3336],{"name":17,"slug":18,"type":15},{"name":23,"slug":24,"type":15},{"name":3203,"slug":3204,"type":15},{"slug":3267,"name":3267,"fn":3268,"description":3269,"org":3338,"tags":3339,"stars":25,"repoUrl":26,"updatedAt":3279},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3340,3341,3342],{"name":3273,"slug":3274,"type":15},{"name":23,"slug":24,"type":15},{"name":3277,"slug":3278,"type":15},{"slug":3344,"name":3344,"fn":3345,"description":3346,"org":3347,"tags":3348,"stars":25,"repoUrl":26,"updatedAt":3352},"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},[3349,3350,3351],{"name":13,"slug":14,"type":15},{"name":3277,"slug":3278,"type":15},{"name":3188,"slug":3189,"type":15},"2026-07-19T05:38:18.364937",{"slug":3354,"name":3354,"fn":3355,"description":3356,"org":3357,"tags":3358,"stars":25,"repoUrl":26,"updatedAt":3365},"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},[3359,3360,3363,3364],{"name":3277,"slug":3278,"type":15},{"name":3361,"slug":3362,"type":15},"Monitoring","monitoring",{"name":3188,"slug":3189,"type":15},{"name":20,"slug":21,"type":15},"2026-07-12T08:21:35.865649",{"slug":3367,"name":3367,"fn":3368,"description":3369,"org":3370,"tags":3371,"stars":25,"repoUrl":26,"updatedAt":3376},"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},[3372,3373,3374,3375],{"name":13,"slug":14,"type":15},{"name":23,"slug":24,"type":15},{"name":3277,"slug":3278,"type":15},{"name":3188,"slug":3189,"type":15},"2026-07-12T08:21:40.961722",{"slug":3378,"name":3378,"fn":3379,"description":3380,"org":3381,"tags":3382,"stars":25,"repoUrl":26,"updatedAt":3386},"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},[3383,3384,3385],{"name":23,"slug":24,"type":15},{"name":3277,"slug":3278,"type":15},{"name":3232,"slug":3233,"type":15},"2026-07-19T05:38:14.336279",144]