Use when writing tests, setting up test frameworks, implementing mocking strategies, or establishing testing best practices (unit, integration, E2E) across any technology stack.
Language-agnostic testing patterns and strategies applicable across all technology stacks.
┌───────┐
│ E2E │ Few, slow, expensive
─┴───────┴─
┌───────────┐
│Integration│ Some, medium speed
─┴───────────┴─
┌───────────────┐
│ Unit │ Many, fast, cheap
─┴───────────────┴─
// Arrange - Set up test data and conditions
const user = createTestUser({ email: 'test@example.com' });
const service = new UserService(mockDb);
// Act - Execute the code under test
const result = await service.createUser(user);
// Assert - Verify the expected outcome
expect(result.id).toBeDefined();
expect(result.email).toBe('test@example.com');
component.test.ts # Unit tests
component.spec.ts # Alternative convention
component.integration.ts # Integration tests
component.e2e.ts # End-to-end tests
Use descriptive names that explain the scenario:
// Pattern: should [expected behavior] when [condition]
describe('UserService', () => {
describe('createUser', () => {
it('should create user when valid data provided', () => {});
it('should throw ValidationError when email is invalid', () => {});
it('should throw DuplicateError when email already exists', () => {});
});
});
describe('User Registration', () => {
describe('given a valid email and password', () => {
describe('when the user submits the form', () => {
it('then creates a new account', () => {});
it('then sends a welcome email', () => {});
});
});
});
| Type | Purpose | Example |
|------|---------|---------|
| Stub | Returns predetermined values | stub.returns(42) |
| Mock | Verifies interactions | expect(mock).toHaveBeenCalled() |
| Spy | Wraps real implementation | spy(realFunction) |
| Fake | Working implementation (simplified) | In-memory database |
| Dummy | Placeholder (not used) | Required parameter |
DO Mock:
DON'T Mock:
// Mock external API
const mockApi = {
getUser: jest.fn().mockResolvedValue({ id: '1', name: 'Test' })
};
// Inject mock
const service = new UserService(mockApi);
const result = await service.getUser('1');
// Verify interaction
expect(mockApi.getUser).toHaveBeenCalledWith('1');
expect(result.name).toBe('Test');
Create reusable factory functions for test data:
// factories/user.ts
export function createTestUser(overrides = {}) {
return {
id: randomUUID(),
email: `test-${Date.now()}@example.com`,
name: 'Test User',
createdAt: new Date(),
...overrides
};
}
// In tests
const user = createTestUser({ name: 'Custom Name' });
Static test data for consistent testing:
// fixtures/users.ts
export const validUser = {
email: 'valid@example.com',
password: 'SecurePass123!'
};
export const invalidEmails = [
'no-at-sign',
'@no-local.com',
'no-domain@',
'spaces in@email.com'
];
// BAD - vague assertion
expect(result).toBeTruthy();
// GOOD - specific assertion
expect(result.success).toBe(true);
expect(result.data.id).toBe('expected-id');
// BAD - multiple unrelated assertions
it('should process order', () => {
expect(order.id).toBeDefined();
expect(order.total).toBe(100);
expect(emailService.send).toHaveBeenCalled();
expect(inventory.reduce).toHaveBeenCalled();
});
// GOOD - focused tests
it('should assign an order ID', () => {
expect(order.id).toBeDefined();
});
it('should calculate correct total', () => {
expect(order.total).toBe(100);
});
it('should send confirmation email', () => {
expect(emailService.send).toHaveBeenCalled();
});
Create domain-specific matchers for readability:
expect.extend({
toBeValidEmail(received) {
const pass = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(received);
return {
pass,
message: () => `expected ${received} to be a valid email`
};
}
});
// Usage
expect('user@example.com').toBeValidEmail();
| Type | Target | Notes | |------|--------|-------| | Line Coverage | 80% | Minimum acceptable | | Branch Coverage | 75% | Test all conditionals | | Function Coverage | 90% | All public APIs | | Critical Paths | 100% | Auth, payments, data integrity |
High coverage ≠ good tests
// 100% coverage but useless test
it('should run without error', () => {
processOrder(order); // No assertions!
});
Focus on:
| Test Type | Target Time | |-----------|-------------| | Unit test | < 10ms | | Integration test | < 1s | | E2E test | < 30s | | Full suite | < 5min |
# Run tests in parallel
vitest --pool=threads
jest --maxWorkers=4
pytest -n auto
go test -parallel 4
Tests should not depend on each other:
// BAD - shared state
let counter = 0;
it('test 1', () => { counter++; });
it('test 2', () => { expect(counter).toBe(1); }); // Fragile!
// GOOD - isolated state
beforeEach(() => { counter = 0; });
it('test 1', () => { counter++; expect(counter).toBe(1); });
it('test 2', () => { counter++; expect(counter).toBe(1); });
Testing strategies applicable to all technology stacks
npx skills add MadAppGang/testing-strategies下载完整 Skill 目录,包含 SKILL.md 及所有相关文件
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer