/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 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
This repository contains the .NET team's curated set of core skills and custom agents for coding agents. For information about the Agent Skills standard, see agentskills.io. 📊 Dashboard - Accuracy and efficiency scoring trends for contained plugins (
Repo: dotnet/skills
Other skills on dotnet-skills.
- /csharp-scripts
Run file-based C# apps with the .NET CLI when the user explicitly wants C#/.NET code without creating a project. Use for C# language/API experiments, one-file C# apps, small multi-file C# apps composed with `#:include`/`#:exclude`, or C# file-based apps linked with `#:ref`. Do
Open skill - /dotnet-pinvoke
Correctly call native (C/C++) libraries from .NET using P/Invoke and LibraryImport. Covers function signatures, string marshalling, memory lifetime, SafeHandle, and cross-platform patterns. USE FOR: writing new P/Invoke or LibraryImport declarations, reviewing or debugging
Open skill - /nuget-trusted-publishing
Set up NuGet trusted publishing (OIDC) on a GitHub Actions repo — replaces long-lived API keys with short-lived tokens. USE FOR: trusted publishing, NuGet OIDC, keyless NuGet publish, migrate from NuGet API key, NuGet/login, secure NuGet publishing. DO NOT USE FOR: publishing to
Open skill - /technology-selection
Guides technology selection and implementation of AI and ML features in .NET 8+ applications using ML.NET, Microsoft.Extensions.AI (MEAI), Microsoft Agent Framework (MAF), GitHub Copilot SDK, ONNX Runtime, and OllamaSharp. Covers the full spectrum from classic ML through modern
Open skill - /configuring-opentelemetry-dotnet
Configure OpenTelemetry distributed tracing, metrics, and logging in ASP.NET Core using the .NET OpenTelemetry SDK. Use when adding observability, setting up OTLP exporters, creating custom metrics/spans, or troubleshooting distributed trace correlation.
Open skill - /convert-blazor-server-to-webapp
Guides conversion of a pre-.NET 8 Blazor Server app into a .NET 8+ Blazor Web App. USE FOR: migrating apps that use AddServerSideBlazor and MapBlazorHub to the AddRazorComponents/MapRazorComponents model, converting _Host.cshtml to an App.razor root component, replacing
Open skill

