testing-best-practices
Testing methodologies, patterns, and best practices for unit, integration, and E2E tests. (project)
When & Why to Use This Skill
This Claude skill provides a comprehensive framework for software testing, encompassing unit, integration, and E2E testing methodologies. It offers standardized patterns like AAA (Arrange, Act, Assert), advanced mocking strategies, and architectural best practices to help developers ensure code reliability, maintainability, and high performance.
Use Cases
- Standardizing unit test structures using the AAA pattern to improve readability and maintenance across development teams.
- Implementing robust mocking and spying strategies for complex dependencies to isolate logic during testing.
- Designing integration tests for APIs and databases to verify seamless communication between system components.
- Setting up end-to-end (E2E) testing workflows with Playwright to validate critical user journeys and UI stability.
- Optimizing software quality by establishing code coverage targets and identifying high-priority edge cases for testing.
| name | testing-best-practices |
|---|---|
| description | Testing methodologies, patterns, and best practices for unit, integration, and E2E tests. (project) |
| allowed-tools | Read, Grep, Glob, Edit, Write, Bash |
Testing Best Practices
Testing Pyramid
/\
/E2E\ <- Few, slow, expensive
/------\
/Integration\ <- Some, moderate speed
/--------------\
/ Unit Tests \ <- Many, fast, cheap
/------------------\
Unit Testing
AAA Pattern
describe('Calculator', () => {
it('should add two numbers correctly', () => {
// Arrange
const calculator = new Calculator();
// Act
const result = calculator.add(2, 3);
// Assert
expect(result).toBe(5);
});
});
Naming Convention
// Pattern: should [expected behavior] when [condition]
it('should throw error when dividing by zero')
it('should return empty array when no items match')
it('should update user when valid data provided')
Test Organization
describe('UserService', () => {
describe('createUser', () => {
it('should create user with valid data')
it('should throw error when email exists')
it('should hash password before saving')
});
describe('deleteUser', () => {
it('should remove user from database')
it('should throw error when user not found')
});
});
Mocking
Function Mocks
const mockFn = jest.fn();
mockFn.mockReturnValue('value');
mockFn.mockResolvedValue('async value');
mockFn.mockRejectedValue(new Error('fail'));
Module Mocks
jest.mock('./database', () => ({
query: jest.fn().mockResolvedValue([]),
}));
Spy on Methods
const spy = jest.spyOn(service, 'method');
expect(spy).toHaveBeenCalledWith(arg1, arg2);
Integration Testing
API Testing
describe('POST /api/users', () => {
it('should create a new user', async () => {
const response = await request(app)
.post('/api/users')
.send({ name: 'John', email: 'john@example.com' })
.expect(201);
expect(response.body.data.name).toBe('John');
});
});
Database Testing
beforeEach(async () => {
await db.migrate.latest();
await db.seed.run();
});
afterEach(async () => {
await db.migrate.rollback();
});
E2E Testing
Playwright Example
test('user can login', async ({ page }) => {
await page.goto('/login');
await page.fill('[name="email"]', 'user@example.com');
await page.fill('[name="password"]', 'password123');
await page.click('button[type="submit"]');
await expect(page).toHaveURL('/dashboard');
});
Code Coverage
Coverage Targets
- Statements: 80%+
- Branches: 75%+
- Functions: 80%+
- Lines: 80%+
Focus Areas
- Critical business logic
- Edge cases and error handling
- Security-sensitive code
Don't Over-Test
- Getters/setters
- Framework code
- Third-party libraries
- Simple transformations
Test Data
Factories
const createUser = (overrides = {}) => ({
id: faker.string.uuid(),
name: faker.person.fullName(),
email: faker.internet.email(),
...overrides,
});
Fixtures
// fixtures/users.json
{
"admin": { "id": "1", "role": "admin" },
"user": { "id": "2", "role": "user" }
}