Skip to content
Development
Skill

/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

From plugin
dotnet-skills
499200 skills17 agents

Claude Code

$ npx -y skills add managedcode/dotnet-skills --skill exp-test-maintainability --agent claude-code

SKILL.md

exp-test-maintainability.SKILL.md
name: exp-test-maintainability
description: "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)."
license: MIT

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 using these framework markers:

| Framework | Test class markers | Test method markers | |-----------|--------------------|---------------------| | MSTest | `[TestClass]` | `[TestMethod]`, `[DataTestMethod]` | | xUnit | *(none — convention-based)* | `[Fact]`, `[Theory]` | | NUnit | `[TestFixture]` | `[Test]`, `[TestCase]`, `[TestCaseSource]` | | TUnit | *(none — convention-based)* | `[Test]` |

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:**

[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:**

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
Read more
@managedcode
Ships withdotnet-skills

Stop explaining .NET to your AI. Start building. We've all been there: asking Claude to use Entity Framework, only to get EF6 patterns in a .NET 8 project. Explaining to Copilot that Blazor Server and Blazor WebAssembly aren't the same thing.

499200 skills17 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
499
Star history of managedcode/dotnet-skills on GitHub, a chart by star-history.com

Other skills on dotnet-skills.

aspnet-core

aspnet-core

Build, debug, modernize, or review ASP.NET Core applications with correct hosting, middleware, security, configuration, logging,…

aspire

aspire

Build, upgrade, and operate Aspire 13.5.x C# or TypeScript application hosts with the current CLI, AppHost, ServiceDefaults,…

avalonia

avalonia

Build and debug Avalonia 11/12 .NET applications with XAML, compiled bindings, MVVM, custom controls, desktop lifetimes, and…

azure-functions

azure-functions

Build, review, or migrate Azure Functions in .NET with correct execution model, isolated worker setup, bindings, DI, and Durable…

blazor

blazor

Build and review Blazor applications across server, WebAssembly, web app, and hybrid scenarios with correct component design,…

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills12d309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc2w293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react3d252k
@facebook@facebookInstall Skill

Questions about exp-test-maintainability.

Which coding agents can use exp-test-maintainability?
exp-test-maintainability installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.