npx skills add ...
npx skills add dotnet/skills --skill test-smell-detection
Audits existing tests in any language using formal, research-backed test smell names and the testsmells.org 19-smell academic taxonomy. Use when the caller asks for an academic or citable test-smell review, named smell categories, or a formal severity-ranked smell assessment. Covers Assertion Roulette, Conditional Test Logic, Mystery Guest, Eager Test, Sleepy Test, Unknown Test, Sensitive Equality, and the rest of the catalog across .NET, Python, JavaScript/TypeScript, Java, Go, Ruby, Rust, Swift, Kotlin, PowerShell, and C++. DO NOT USE FOR a quick pragmatic test review (use test-anti-patterns), writing or running tests, framework migration, coverage, or assertion-diversity metrics.
npx skills add dotnet/skills --skill test-smell-detection
Audit test code with the academic taxonomy, code evidence, calibrated framework idioms, and fixes native to the codebase.
test-analysis-extensions and read the
matching language extension.| Evidence | Academic finding | Do | Never |
|---|---|---|---|
Assertion behavior changes behind if, switch, or branching loops | Conditional Test Logic | Split cases or parameterize them | Flag table-driven or parametrized tests merely because a runner loop exists |
| A test relies on an undeclared file, network service, environment value, or database | Mystery Guest or Resource Optimism | Make the dependency explicit and hermetic; distinguish the two using the full catalog | Condemn an integration test merely for exercising its declared real resource |
| Fixed wall-clock sleep waits for an outcome | Sleepy Test | Await or poll the condition with a timeout | Downgrade it only because the test is an integration test |
| Executable test has no assertion, expected-exception marker, or mock verification | Unknown Test | Assert the observable outcome | Call an empty body Unknown Test; the formal name is Empty Test |
| Async assertion/coroutine is created but not awaited or returned | Critical non-catalog false-pass defect | Report it separately and show the required await/return | Force it into Unknown Test; the assertion statement exists |
| One test exercises many unrelated production behaviors | Eager Test | Separate behavior-focused tests | Flag a deliberate end-to-end workflow without considering its scope |
| Expected numeric literal has no local meaning | Magic Number Test | Name the domain value or derive it from setup | Flag count == 3 immediately after adding three items |
Assertion depends on ToString, repr, description, or display formatting that is not the contract | Sensitive Equality | Assert stable fields or use a structural matcher | Flag a test whose explicit contract is the formatted string |
| Test manually manages expected exception flow | Exception Handling | Use the framework's exception assertion and check meaningful details | Claim a capture-and-assert test verifies nothing |
| Shared setup creates state irrelevant to the tests that receive it | General Fixture | Remove unused state or narrow the fixture; rank cheap state low | Condemn relevant shared setup merely because it is shared |
| Test is disabled or skipped | Ignored Test | Report every skip, but rank a tracked, reasoned skip below an unexplained one | Clear a skip because its reason is good, or give both the same urgency |
Apply these before assigning a finding:
assert, Pester
Should -Invoke, and expected-exception constructs are assertions..each, RSpec data tables, Pester -ForEach, and Catch2
SECTION/GENERATE are not Conditional Test Logic by themselves.if err != nil { t.Fatal(...) } is idiomatic assertion flow, not
Exception Handling.SECTION and GENERATE are runner-controlled case expansion, and
REQUIRE is a real assertion. When those are the only suspicious constructs,
the academic-smell verdict is clean. Do not reverse that verdict because
the test could have broader behavioral coverage.await for a void or otherwise non-awaitable API. If production
work is synchronous, remove the sleep and assert immediately.Severity follows demonstrated risk, not a fixed label copied from the catalog:
State the reason for the assigned severity. Downgrade or omit a finding when the surrounding test type makes the pattern intentional.
Scale the response to the input:
Every reported smell must have a formal taxonomy name, precise location, evidence from the code, practical risk, and a concrete framework-correct fix.