> test-quality-analysis
Detect test smells, overmocking, flaky tests, and coverage issues. Analyze test effectiveness, maintainability, and reliability. Use when reviewing tests or improving test quality.
curl "https://skillshub.wtf/secondsky/claude-skills/test-quality-analysis?format=md"Test Quality Analysis
Expert knowledge for analyzing and improving test quality - detecting test smells, overmocking, insufficient coverage, and testing anti-patterns.
Core Dimensions
- Correctness: Tests verify the right behavior
- Reliability: Tests are deterministic, not flaky
- Maintainability: Tests are easy to understand
- Performance: Tests run quickly
- Coverage: Tests cover critical code paths
- Isolation: Tests don't depend on external state
Test Smells
Overmocking
Problem: Mocking too many dependencies makes tests fragile.
// ❌ BAD: Overmocked
test('calculate total', () => {
const mockAdd = vi.fn(() => 10)
const mockMultiply = vi.fn(() => 20)
// Testing implementation, not behavior
})
// ✅ GOOD: Mock only external dependencies
test('calculate order total', () => {
const mockPricingAPI = vi.fn(() => ({ tax: 0.1 }))
const total = calculateTotal(order, mockPricingAPI)
expect(total).toBe(38)
})
Detection: More than 3-4 mocks, mocking pure functions, complex mock setup.
Fix: Mock only I/O boundaries (APIs, databases, filesystem).
Fragile Tests
Problem: Tests break with unrelated code changes.
// ❌ BAD: Tests implementation details
await page.locator('.form-container > div:nth-child(2) > button').click()
// ✅ GOOD: Semantic selector
await page.getByRole('button', { name: 'Submit' }).click()
Flaky Tests
Problem: Tests pass or fail non-deterministically.
// ❌ BAD: Race condition
test('loads data', async () => {
fetchData()
await new Promise(resolve => setTimeout(resolve, 1000))
expect(data).toBeDefined()
})
// ✅ GOOD: Proper async handling
test('loads data', async () => {
const data = await fetchData()
expect(data).toBeDefined()
})
Poor Assertions
// ❌ BAD: Weak assertion
test('returns users', async () => {
const users = await getUsers()
expect(users).toBeDefined() // Too vague!
})
// ✅ GOOD: Strong, specific assertions
test('creates user with correct attributes', async () => {
const user = await createUser({ name: 'John' })
expect(user).toMatchObject({
id: expect.any(Number),
name: 'John',
})
})
Analysis Tools
# Vitest coverage (prefer bun)
bun test --coverage
open coverage/index.html
# Check thresholds
bun test --coverage --coverage.thresholds.lines=80
# pytest-cov (Python)
uv run pytest --cov --cov-report=html
open htmlcov/index.html
Best Practices Checklist
Unit Test Quality (FIRST)
- Fast: Tests run in milliseconds
- Isolated: No dependencies between tests
- Repeatable: Same results every time
- Self-validating: Clear pass/fail
- Timely: Written alongside code
Mock Guidelines
- Mock only external dependencies
- Don't mock business logic or pure functions
- Use real implementations when possible
- Limit to 3-4 mocks per test maximum
Coverage Goals
- 80%+ line coverage for business logic
- 100% for critical paths (auth, payment)
- All error paths tested
- Boundary conditions tested
Test Structure (AAA Pattern)
test('user registration', async () => {
// Arrange
const userData = { email: 'user@example.com' }
// Act
const user = await registerUser(userData)
// Assert
expect(user.email).toBe('user@example.com')
})
Code Review Checklist
- Tests verify behavior, not implementation
- Assertions are specific and meaningful
- No flaky tests (timing, ordering issues)
- Proper async/await usage
- Test names clearly describe behavior
- Minimal code duplication
- Critical paths have tests
- Both happy path and error cases covered
Common Anti-Patterns
Testing Implementation Details
// ❌ BAD
const spy = vi.spyOn(Math, 'sqrt')
calculateDistance()
expect(spy).toHaveBeenCalled() // Testing how, not what
// ✅ GOOD
const distance = calculateDistance({ x: 0, y: 0 }, { x: 3, y: 4 })
expect(distance).toBe(5) // Testing output
Mocking Too Much
// ❌ BAD
const mockAdd = vi.fn((a, b) => a + b)
// ✅ GOOD: Use real implementations
import { add } from './utils'
// Only mock external services
const mockPaymentGateway = vi.fn()
See Also
vitest-testing- TypeScript/JavaScript testingplaywright-testing- E2E testingmutation-testing- Validate test effectiveness
> related_skills --same-repo
> zustand-state-management
--- name: zustand-state-management description: Zustand state management for React with TypeScript. Use for global state, Redux/Context API migration, localStorage persistence, slices pattern, devtools, Next.js SSR, or encountering hydration errors, TypeScript inference issues, persist middleware problems, infinite render loops. Keywords: zustand, state management, React state, TypeScript state, persist middleware, devtools, slices pattern, global state, React hooks, create store, useBoundS
> zod
TypeScript-first schema validation and type inference. Use for validating API requests/responses, form data, env vars, configs, defining type-safe schemas with runtime validation, transforming data, generating JSON Schema for OpenAPI/AI, or encountering missing validation errors, type inference issues, validation error handling problems. Zero dependencies (2kb gzipped).
> xss-prevention
--- name: xss-prevention description: XSS attack prevention with input sanitization, output encoding, Content Security Policy. Use for user-generated content, rich text editors, web application security, or encountering stored XSS, reflected XSS, DOM manipulation, script injection errors. Keywords: sanitization, HTML-encoding, DOMPurify, CSP, Content-Security-Policy, rich-text-editor, user-input, escaping, innerHTML, DOM-manipulation, stored-XSS, reflected-XSS, input-validation, output-encodi
> wordpress-plugin-core
--- name: wordpress-plugin-core description: WordPress plugin development with hooks, security, REST API, custom post types. Use for plugin creation, $wpdb queries, Settings API, or encountering SQL injection, XSS, CSRF, nonce errors. Keywords: wordpress plugin development, wordpress security, wordpress hooks, wordpress filters, wordpress database, wpdb prepare, sanitize_text_field, esc_html, wp_nonce, custom post type, register_post_type, settings api, rest api, admin-ajax, wordpress sql inj