Testing pyramid
Focus on many unit tests, fewer integration tests, few end-to-end. Aim for fast, deterministic tests; mock external services.
Unit vs Integration vs E2E
Unit: test a function/component in isolation. Integration: verify modules working together. E2E: simulate user flows in a real environment.
Jest basics
Matchers: toEqual/toBe/toThrow. Setup/teardown: beforeEach/afterEach. Mocks/spies: jest.fn, jest.mock. Snapshot testing for UI.
React Testing Library
Test via user-centric queries (getByRole, getByText). Avoid testing implementation details; assert behavior and accessibility.
Cypress vs Playwright
Cypress: great DX, runs in browser. Playwright: multi-browser automation, powerful fixtures, parallelization. Choose based on needs.
Stubs, Mocks, Fakes
Stubs: controlled responses. Mocks: verify interactions. Fakes: lightweight implementations (e.g., in-memory DB) for faster tests.
Coverage and quality gates
Use coverage as a heuristic, not a goal. Enforce minimum coverage/linting in CI to prevent regressions. Target critical paths first.
TDD vs BDD
TDD emphasizes writing tests first to drive design; BDD focuses on behavior/specs and readable scenarios.
Flaky tests
Identify and fix nondeterminism (timing, network, shared state). Use retries temporarily, then stabilize through isolation and mocking.
Property-based testing
Generate inputs to validate invariants across a wide range (fast-check/pytest-hypothesis). Great for algorithms and parsers.
Contract testing
Validate interactions between services using consumer-driven contracts (Pact) to avoid breaking changes.
Performance tests
Measure throughput/latency with load tools (k6/JMeter); set budgets and track regressions in CI.