exp-test-maintainability
Detects duplicate boilerplate, copy-paste tests, and structural maintainability issues across .NET test suites. Use when the user asks to reduce repetition, consolidate similar test methods, convert copy-paste tests to data-driven parameterized tests, suggest a better test structure, or identify refactoring opportunities. Identifies repeated construction, assertion patterns, copy-paste methods convertible to DataRow/Theory/TestCase, redundant setup/teardown, and shared infrastructure. Produces an analysis report with concrete before/after suggestions. Works with MSTest, xUnit, NUnit, and TUnit. DO NOT USE FOR: writing new tests (use writing-mstest-tests), reviewing test quality or anti-patterns (use test-anti-patterns), or deep mock auditing (use exp-mock-usage-analysis).
What this skill does
# Test Maintainability Assessment
Analyze .NET test code for maintainability issues: duplicated boilerplate, copy-paste test methods, and structural repetition across test methods and classes. Produce a report of refactoring opportunities with concrete before/after suggestions. The goal is analysis only — do not modify any files.
## When to Use
- User asks to find duplicated code or boilerplate in tests
- User wants to know where test code can be DRY-ed up
- User asks to reduce test duplication, improve test readability, or clean up test boilerplate
- User asks for refactoring opportunities in a test suite
- User wants to identify shared setup or teardown candidates
- User asks "what patterns repeat across my tests?"
- User wants to centralize test data, introduce builders or helpers
## When Not to Use
- User wants to write new tests from scratch (use `writing-mstest-tests`)
- User wants to detect anti-patterns or code smells (use `test-anti-patterns`)
- User wants to actually perform the refactoring (help them directly, this skill only analyzes)
## Inputs
| Input | Required | Description |
|-------|----------|-------------|
| Test code | Yes | One or more test files or a test project directory to analyze |
| Production code | No | The code under test, for context on what abstractions might help |
| Scope | No | Whether to analyze within a single class or across multiple classes |
## Workflow
### Step 1: Gather the test code
Read all test files the user provides or references. If the user points to a directory or project, scan for all test files — see the `dotnet-test-frameworks` skill for framework-specific markers.
### Step 2: Identify maintainability issues
Scan for these categories:
#### Category 1: Repeated object construction
Look for the same object being constructed in 3+ test methods with identical or near-identical parameters.
**Indicators:**
- `new ClassName(...)` appearing with identical arguments in multiple tests
- Multiple tests creating the same "system under test" with similar configuration
- Repeated mock/fake/stub creation with the same setup
**Potential refactorings:**
- Extract a factory method or test helper (e.g., `CreateSut()`, `CreateDefaultOrder()`)
- Use `[TestInitialize]`/constructor/`[SetUp]` for shared construction
- Introduce a builder pattern for complex objects with many variations
**Example — before:**
```csharp
[TestMethod]
public void Process_ValidOrder_Succeeds()
{
var logger = new FakeLogger();
var email = new FakeEmailService();
var inventory = new FakeInventory(stock: 100);
var processor = new OrderProcessor(logger, email, inventory);
// ...
}
[TestMethod]
public void Process_EmptyItems_Fails()
{
var logger = new FakeLogger();
var email = new FakeEmailService();
var inventory = new FakeInventory(stock: 100);
var processor = new OrderProcessor(logger, email, inventory);
// ...
}
```
**After — extract factory:**
```csharp
private static OrderProcessor CreateProcessor(int stock = 100)
{
return new OrderProcessor(new FakeLogger(), new FakeEmailService(), new FakeInventory(stock));
}
```
#### Category 2: Repeated assertion patterns
Look for the same sequence of assertions appearing in 3+ test methods.
**Indicators:**
- Multiple tests asserting the same set of properties on a result object
- Repeated null-check-then-value-check sequences
- Same collection of `Assert.AreEqual` calls across methods
**Potential refactorings:**
- Extract a custom assertion helper (e.g., `AssertValidOrder(order, expectedTotal, expectedStatus)`)
- Use framework-specific assertion extensions
- Introduce a `Verify` method that checks a standard set of properties
#### Category 3: Copy-paste test methods
Look for test methods with near-identical bodies differing only in input values or a single parameter.
**Indicators:**
- 3+ methods with the same structure but different literal values
- Methods that could be collapsed into `[DataRow]`/`[Theory]`/`[TestCase]`
- Test names that follow a pattern like `Method_Input1_Result`, `Method_Input2_Result`
**Potential refactorings:**
- Convert to parameterized tests with `[DataRow]`/`[InlineData]`/`[TestCase]`
- Use `[DynamicData]`/`[MemberData]`/`[TestCaseSource]` for complex inputs
- Prefer `[DataRow]` with `DisplayName` over `[DynamicData]` when all values are compile-time constants. Reserve `[DynamicData]` for computed or complex values.
- Add `DisplayName` for non-obvious parameter values. `[DataRow("Gold", 100.0, 90.0)]` is self-explanatory; `[DataRow(3, 7, 42)]` is not.
#### Category 4: Duplicated setup/teardown logic
Look for initialization or cleanup code repeated across test classes.
**Indicators:**
- Multiple `[TestInitialize]`/`[SetUp]` methods with similar bodies
- Repeated database seeding, file creation, or HTTP client configuration
- Same `using`/`IDisposable` cleanup pattern across classes
**Potential refactorings:**
- Extract a shared test base class or fixture
- Use composition with a shared helper class
- Create a test context factory
#### Category 5: Repeated test infrastructure
Look for structural patterns shared across test classes.
**Indicators:**
- Same mock interfaces configured identically in multiple classes
- Repeated `HttpClient` setup with similar `DelegatingHandler` patterns
- Same logging/configuration scaffolding across test classes
**Potential refactorings:**
- Extract a shared test fixture or helper library
- Create reusable fake implementations
- Introduce a test harness class
### Step 3: Apply calibration rules
Before reporting, filter findings through these rules:
- **Only report at 3+ occurrences.** Two similar setups are not boilerplate — they may be intentional clarity.
- **Don't flag simple constructors.** `new Calculator()` or `new List<int>()` is not meaningful boilerplate. Don't recommend builders for `new User(1, "Alice")` either.
- **Respect intentional verbosity.** If each test is self-contained and reads clearly on its own, explicit setup per test is a valid choice. Note it but don't flag it as a problem.
- **Distinguish structural similarity from true duplication.** Tests that follow AAA (Arrange-Act-Assert) will look similar by nature. Only flag when the actual code (not just the structure) is duplicated.
- **Consider the blast radius of refactoring.** A helper shared across 20 tests creates coupling. Note the trade-off.
- **If tests are already well-maintained, say so.** A report finding only minor opportunities is perfectly valid. Acknowledge what's already good.
### Step 4: Report findings
Present findings in this structure:
1. **Summary** — How many patterns found, broken down by category. If the test suite is clean, lead with that.
2. **Findings by category** — For each pattern found:
- Category name and description
- Locations: list the specific test methods and files involved
- The duplicated code pattern (show a representative sample)
- Suggested refactoring with a concrete before/after example
- Estimated impact: how many lines/methods would be simplified
3. **Refactoring priority** — Rank findings by:
- Occurrence count (more occurrences = higher value)
- Complexity of the duplicated code (complex setup > simple construction)
- Risk (low-risk extractions first)
4. **Trade-offs** — For each suggestion, note:
- What readability is gained
- What locality/independence is lost
- Whether it's worth it given the occurrence count
## Validation
- [ ] Every finding includes specific file and method locations
- [ ] Every finding shows the actual duplicated code, not just a description
- [ ] Every suggestion includes a concrete before/after example
- [ ] Findings are filtered through the 3+ occurrence threshold
- [ ] Simple constructors are not flagged
- [ ] Trade-offs are acknowledged for each suggestion
- [ ] If tests are clean, the report says so upfront
## Common Pitfalls
| Pitfall | Solution |
|---------|----------|
| Flagging ARelated in Writing & Docs
jax-development
IncludedUse this skill when the user is writing, debugging, profiling, refactoring, reviewing, benchmarking, parallelising, exporting, or explaining JAX code, or when they mention JAX, jax.numpy, jit, grad, value_and_grad, vmap, scan, lax, random keys, pytrees, jax.Array, sharding, Mesh, PartitionSpec, NamedSharding, pmap, shard_map, Pallas, XLA, StableHLO, checkify, profiler, or the JAX repo. It helps turn NumPy or PyTorch-style code into pure functional JAX, fix tracer/control-flow/shape/PRNG bugs, remove recompiles and host-device syncs, choose transforms and sharding strategies, inspect jaxpr/lowering/IR, and benchmark compiled code correctly.
nature-article-writer
IncludedDrafts, rewrites, diagnostically critiques, and style-calibrates primary research manuscripts for Nature and Nature Portfolio journals. Use when the user wants a Nature-style title, summary paragraph or abstract, introduction, results, discussion, methods, figure legends, presubmission enquiry, cover letter, reviewer response, or when a scientific draft sounds generic, jargon-heavy, structurally weak, or AI-ish and needs precise, broad-reader-friendly prose without inventing data, analyses, or references. Best for primary research articles and letters rather than reviews or press releases unless explicitly adapting one.
deckrd
IncludedDocument-driven framework that derives requirements, specifications, implementation plans, and executable tasks from goals through structured AI dialogue. Use when user says "write requirements", "create spec", "plan implementation", "derive tasks", "structure this feature", "break down into tasks", or "document this module". Also use for reverse engineering existing code into docs (/deckrd rev). Do NOT use for direct code writing — use /deckrd-coder after tasks are generated. Do NOT use when the user only wants to run or fix existing code without planning.
clinical-decision-support
IncludedGenerate professional clinical decision support (CDS) documents for pharmaceutical and clinical research settings, including patient cohort analyses (biomarker-stratified with outcomes) and treatment recommendation reports (evidence-based guidelines with decision algorithms). Supports GRADE evidence grading, statistical analysis (hazard ratios, survival curves, waterfall plots), biomarker integration, and regulatory compliance. Outputs publication-ready LaTeX/PDF format optimized for drug development, clinical research, and evidence synthesis.
handling-sf-data
IncludedSalesforce data operations with 130-point scoring. Use this skill to create, update, delete, bulk import/export, generate test data, and clean up org records using sf CLI and anonymous Apex. TRIGGER when: user creates test data, performs bulk import/export, uses sf data CLI commands, needs data factory patterns for Apex tests, or needs to seed/clean records in a Salesforce org. DO NOT TRIGGER when: SOQL query writing only (use querying-soql), Apex test execution (use running-apex-tests), or metadata deployment (use deploying-metadata).
accelint-ac-to-playwright
IncludedConvert and validate acceptance criteria for Playwright test automation. Use when user asks to (1) review/evaluate/check if AC are ready for automation, (2) assess if AC can be converted as-is, (3) validate AC quality for Playwright, (4) turn AC into tests, (5) generate tests from acceptance criteria, (6) convert .md bullets or .feature Gherkin files to Playwright specs, (7) create test automation from requirements. Handles both bullet-style markdown and Gherkin syntax with JSON test plan generation and validation.