
Test Maintainability Assessment
FreeAnalyze .NET tests for maintainability issues.
Free · Opens the source repo
What Test Maintainability Assessment does
The Test Maintainability Assessment skill is designed to help developers identify and address maintainability issues within their .NET test suites. By analyzing the provided test code, this skill detects patterns of duplicated boilerplate, copy-paste test methods, and structural issues that could hinder the readability and efficiency of tests. The skill produces a comprehensive analysis report that highlights specific areas for improvement, offering concrete before-and-after suggestions to streamline test code and enhance maintainability.
This skill is particularly useful for teams looking to improve their testing practices by reducing redundancy and promoting the DRY (Don't Repeat Yourself) principle in their test suites. It scans for repeated object constructions, assertion patterns, and setup/teardown logic, providing actionable insights on how to refactor tests for better organization and clarity. The skill supports various testing frameworks, including MSTest, xUnit, NUnit, and TUnit, making it versatile for different .NET projects.
When using this skill, developers can expect to receive detailed feedback on where their test code can be optimized. For instance, it may suggest extracting factory methods for common object constructions or converting similar test methods into parameterized tests. This not only helps in maintaining cleaner code but also fosters a culture of continuous improvement within development teams.
Overall, the Test Maintainability Assessment skill is an essential tool for developers who want to ensure their test suites are efficient, readable, and maintainable over time. By leveraging this skill, teams can enhance their testing strategies and ultimately improve the quality of their software products.
When to use it
Use this skill when you need to analyze existing test code for duplication and structural issues, or when seeking refactoring opportunities.
When not to use it
This skill is not suitable for writing new tests or performing actual code refactoring; it only provides analysis and suggestions.
What you can build with it
Identifying Duplicate Code
A developer wants to find duplicated code in their test suite to improve maintainability and reduce redundancy.
Refactoring Test Methods
A team seeks to consolidate similar test methods into parameterized tests to enhance readability and reduce boilerplate.
Improving Test Structure
A project manager asks for an analysis of the test suite to identify areas where the structure can be improved for better organization.
How to install Test Maintainability Assessment
View source1. Install with the skills CLI
npx skills add dotnet/skills/exp-test-maintainability --agent claude-code2. Or install it manually
Download the skill folder and drop it into ~/.claude/skills/ for all projects, or .claude/skills/ to scope it to one repo. Restart Claude Code so it picks up the new skill.
Anthropic's agentic coding CLI, and the reference implementation of Agent Skills. Drop a skill folder into ~/.claude/skills and Claude Code loads it automatically whenever a task matches the skill's description. Claude Code docs
Inside SKILL.md
Written by dotnetTest 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.AreEqualcalls across methods
Potential refactorings:
- Extract a custom assertion helper (e.g.,
AssertValidOrder(order, expectedTotal, expectedStatus)) - Use framework-specific assertion extensions
- Introduce a
Verifymethod 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]withDisplayNameover[DynamicData]when all values are compile-time constants. Reserve[DynamicData]for computed or complex values. - Add
DisplayNamefor 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/IDisposablecleanup 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
HttpClientsetup with similarDelegatingHandlerpatterns - 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()ornew List<int>()is not meaningful boilerplate. Don't recommend builders fornew 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:
- Summary — How many patterns found, broken down by category. If the test suite is clean, lead with that.
- 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
- 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)
- 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 AAA structure as duplication | The Arrange-Act-Assert pattern is not boilerplate — flag only when the actual code repeats |
| Suggesting extraction for 2 occurrences | Wait for 3+ before recommending extraction |
| Recommending base classes for everything | Prefer composition (helpers, factories) over inheritance |
| Ignoring the readability cost | Every extraction adds indirection — note the trade-off |
Flagging simple new X() as boilerplate | Only flag complex construction with multiple parameters or configuration |
| Recommending DRY at the expense of test isolation | Tests that share mutable state through helpers become coupled — warn about this |
Frequently asked questions about Test Maintainability Assessment
Similar skills
React Composition Patterns
Streamline your React component architecture with proven patterns.
Pester Should Migration
Easily convert Pester v5 assertions to v6 syntax.
Radix to Base UI Migration
Seamlessly migrate React components from Radix UI to Base UI.
Migrate Next.js to Vinext
Seamlessly transition your Next.js projects to Vinext.
WinUI 3 Migration Guide
Streamline your UWP to WinUI 3 migration process.
Refactor
Enhance code maintainability without altering behavior.
