Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Automatically activated when user asks about test quality, code coverage, test reliability, test maintainability, or wants to analyze their test suite. Provides framework-agnostic test quality analysis and improvement recommendations. Does NOT provide framework-specific patterns - use jest-testing or playwright-testing for those.
.claude/skills/aiskillstore-analyzing-test-quality/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-09 | ✗→✓ | ▲ Improved | 123% | 0% |
| case-01 | ✓→✓ | = Same ✓ | 44% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 109% | 0% |
| case-03 | ✓→✓ | = Same ✓ | 182% | 0% |
| case-04 | ✓→✓ | = Same ✓ | 223% | 0% |
You are an expert in test quality analysis with deep knowledge of testing principles, patterns, and metrics that apply across all testing frameworks.
Claude should automatically invoke this skill when:
Use {baseDir} to reference files in this skill directory:
{baseDir}/scripts/{baseDir}/references/{baseDir}/assets/This skill includes ready-to-use resources in {baseDir}:
Tests accurately verify intended behavior:
Tests are easy to understand:
Tests are easy to modify:
Tests produce consistent results:
Tests run efficiently:
typescript// BAD: Shared mutable state let count = 0; beforeEach(() => count++); // GOOD: Reset in setup let count: number; beforeEach(() => { count = 0; });
Mocking too much hides bugs and makes tests brittle.
typescript// BAD: Mock everything - test only verifies mocks // Jest jest.mock('./dep1'); jest.mock('./dep2'); jest.mock('./dep3'); // Vitest vi.mock('./dep1'); vi.mock('./dep2'); vi.mock('./dep3'); // GOOD: Mock boundaries only // Mock external services, keep internal logic real mock('./api'); // External service only // Test actual business logic
typescript// BAD: Timing dependent await delay(100); expect(element).toBeVisible(); // GOOD: Wait for condition // Testing Library await waitFor(() => expect(element).toBeVisible()); // Playwright await expect(element).toBeVisible();
typescript// BAD: Hidden dependencies test('should process', () => { const result = process(); // Uses global data expect(result).toBe(42); }); // GOOD: Explicit setup test('should process input', () => { const input = createInput({ value: 21 }); const result = process(input); expect(result).toBe(42); });
typescript// BAD: Multiple unrelated assertions test('should work', () => { expect(user.name).toBe('John'); expect(items.length).toBe(3); expect(total).toBe(100); }); // GOOD: Focused assertions test('should set user name', () => { expect(user.name).toBe('John'); }); test('should have correct item count', () => { expect(items).toHaveLength(3); });
Mutation testing validates test effectiveness by modifying code and checking if tests catch the changes.
bash# Install Stryker npm install -D @stryker-mutator/core # For specific frameworks npm install -D @stryker-mutator/jest-runner # Jest npm install -D @stryker-mutator/vitest-runner # Vitest npm install -D @stryker-mutator/mocha-runner # Mocha # Initialize configuration npx stryker init
javascript// stryker.conf.js module.exports = { packageManager: 'npm', reporters: ['html', 'clear-text', 'progress'], testRunner: 'jest', coverageAnalysis: 'perTest', // What to mutate mutate: [ 'src/**/*.ts', '!src/**/*.test.ts', '!src/**/*.spec.ts', ], // Mutation types to use mutator: { excludedMutations: [ 'StringLiteral', // Skip string mutations ], }, // Thresholds thresholds: { high: 80, low: 60, break: 50, // Fail CI if below this }, };
Mutation score: 85%
Killed: 170 | Survived: 30 | Timeout: 5 | No coverage: 10High score (>80%): Tests are effective Medium score (60-80%): Some weak areas Low score (<60%): Tests need significant improvement
Boundary mutations: < changed to <=
typescript// Mutation survives if tests don't check boundary if (value < 10) { ... } // Changed to: value <= 10
Arithmetic mutations: + changed to -
typescript// Mutation survives if result isn't precisely checked return a + b; // Changed to: a - b
Boolean mutations: && changed to ||
typescript// Mutation survives if both conditions aren't tested if (a && b) { ... } // Changed to: a || b
yaml# GitHub Actions - name: Run mutation tests run: npx stryker run - name: Upload Stryker report uses: actions/upload-artifact@v3 with: name: stryker-report path: reports/mutation/
javascript// Recommended minimums { statements: 80, branches: 75, functions: 80, lines: 80 }
Mutation testing modifies code to check if tests catch the changes:
When analyzing test quality:
When analyzing coverage:
When auditing for reliability:
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-09 | fail→pass | 10,483 | 14,596 | +39% | 1 | 1 | 0% | 1,781 | 3,974 | +123% | 0 | 0 | — |
case-01 | pass→pass | 22,998 | 18,825 | -18% | 1 | 1 | 0% | 3,551 | 5,126 | +44% | 0 | 0 | — |
case-02 | pass→pass | 12,812 | 12,814 | +0% | 1 | 1 | 0% | 1,789 | 3,732 | +109% | 0 | 0 | — |
case-03 | pass→pass | 7,772 | 8,199 | +5% | 1 | 1 | 0% | 1,384 | 3,909 | +182% | 0 | 0 | — |
case-04 | pass→pass | 12,103 | 8,386 | -31% | 1 | 1 | 0% | 1,143 | 3,690 | +223% | 0 | 0 | — |
case-05 | fail→fail | 13,194 | 8,700 | -34% | 1 | 1 | 0% | 1,380 | 3,898 | +182% | 0 | 0 | — |
case-06 | pass→pass | 14,903 | 17,474 | +17% | 1 | 1 | 0% | 1,631 | 3,535 | +117% | 0 | 0 | — |
case-07 | pass→pass | 12,985 | 19,930 | +53% | 1 | 1 | 0% | 2,074 | 4,488 | +116% | 0 | 0 | — |
case-08 | pass→pass | 17,105 | 19,336 | +13% | 1 | 1 | 0% | 2,068 | 4,936 | +139% | 0 | 0 | — |
case-10 | pass→pass | 20,424 | 15,825 | -23% | 1 | 1 | 0% | 2,640 | 4,223 | +60% | 0 | 0 | — |
case-11 | pass→pass | 9,326 | 11,092 | +19% | 1 | 1 | 0% | 1,478 | 4,246 | +187% | 0 | 0 | — |
case-12 | pass→pass | 11,586 | 11,407 | -2% | 1 | 1 | 0% | 2,115 | 4,362 | +106% | 0 | 0 | — |
case-13 | pass→pass | 17,503 | 10,546 | -40% | 1 | 1 | 0% | 2,168 | 4,237 | +95% | 0 | 0 | — |
case-14 | pass→pass | 8,567 | 5,417 | -37% | 1 | 1 | 0% | 1,334 | 3,253 | +144% | 0 | 0 | — |
case-15 | pass→pass | 19,468 | 15,942 | -18% | 1 | 1 | 0% | 2,374 | 4,913 | +107% | 0 | 0 | — |
case-16 | pass→pass | 14,733 | 21,274 | +44% | 1 | 1 | 0% | 2,312 | 4,985 | +116% | 0 | 0 | — |
case-17 | pass→pass | 9,219 | 11,411 | +24% | 1 | 1 | 0% | 763 | 3,443 | +351% | 0 | 0 | — |
case-18 | pass→pass | 8,293 | 10,484 | +26% | 1 | 1 | 0% | 581 | 3,363 | +479% | 0 | 0 | — |
case-19 | pass→pass | 17,474 | 14,900 | -15% | 1 | 1 | 0% | 2,092 | 3,948 | +89% | 0 | 0 | — |
case-20 | pass→pass | 9,678 | 9,314 | -4% | 1 | 1 | 0% | 768 | 3,078 | +301% | 0 | 0 | — |
case-21 | pass→pass | 16,022 | 13,617 | -15% | 1 | 1 | 0% | 1,829 | 3,888 | +113% | 0 | 0 | — |
case-22 | pass→pass | 14,218 | 11,774 | -17% | 1 | 1 | 0% | 1,541 | 3,459 | +124% | 0 | 0 | — |
case-23 | pass→pass | 12,567 | 13,821 | +10% | 1 | 1 | 0% | 1,322 | 3,851 | +191% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of +4 percentage points is the difference between those two pass rates over the 23 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.