/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
$ npx -y skills add managedcode/dotnet-skills --skill exp-test-maintainability --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/exp-test-maintainability
Context preview
The summary Claude sees to decide when to auto-load this skill.
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
SKILL.md
exp-test-maintainability.SKILL.mdname: 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
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
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.
Repo: managedcode/dotnet-skills
Other skills on dotnet-skills.
- /aspnet-core
Build, debug, modernize, or review ASP.NET Core applications with correct hosting, middleware, security, configuration, logging, and deployment patterns on current .NET. USE FOR: working on ASP.NET Core apps, services, or middleware; changing auth, routing, configuration,
Open skill - /aspire
Build, upgrade, and operate Aspire 13.4.x C# or TypeScript application hosts with the current CLI, AppHost, ServiceDefaults, integrations, dashboard, testing, MCP, and deployment patterns for distributed apps. USE FOR: Aspire.AppHost.Sdk, Aspire.Hosting.*,
Open skill - /azure-functions
Build, review, or migrate Azure Functions in .NET with correct execution model, isolated worker setup, bindings, DI, and Durable Functions patterns. USE FOR: working on Azure Functions in .NET; migrating from the in-process model to the isolated worker model; adding Durable
Open skill - /blazor
Build and review Blazor applications across server, WebAssembly, web app, and hybrid scenarios with correct component design, state flow, rendering, and hosting choices. USE FOR: building interactive web UIs with C# instead of JavaScript; choosing between Server, WebAssembly, or
Open skill - /entity-framework6
Maintain or migrate EF6-based applications with realistic guidance on what to keep, what to modernize, and when EF Core is or is not the right next step. USE FOR: EF6 codebases; runtime versus ORM migration decisions; EDMX, code-first, ObjectContext, and legacy data-access
Open skill - /entity-framework-core
Design, tune, or review EF Core data access with proper modeling, migrations, query translation, performance, and lifetime management for modern .NET applications. USE FOR: DbContext, migrations, model configuration, EF queries, tracking, loading, performance, transactions, and
Open skill

