Unit testing: test một function/class isolated, mock tất cả external dependencies — nhanh (<1ms), stable, dễ debug khi fail (chính xác biết chỗ nào sai), không cần external services.
- Tốt cho: algorithms, business logic, pure functions, utilities.
- Integration testing: test interaction giữa multiple components/services với real hoặc minimal-mock dependencies — ví dụ test API handler với real database (test container), test service với real HTTP client.
- Chậm hơn (100ms-1s), phát hiện bugs ở boundary (schema mismatch, query lỗi, API contract violation) mà unit tests không thể catch.
- Supertest pattern (Node.js): const app = express(); const response = await request(app).get('/api/users').expect(200) — test Express routes với real middleware stack, mock chỉ external services.
- Test containers: spin up real PostgreSQL/Redis trong Docker cho tests — deterministic, isolated, cleanup sau tests.
- Contract tests thay thế integration tests trong microservices khi services owned bởi different teams.
- Testing Library philosophy: 'The more your tests resemble the way your software is used, the more confidence they can give you' — integration tests thường cho more confidence per test than unit tests.
- Mock database vs real database: mock nhanh hơn nhưng có thể miss SQL syntax errors, constraint violations, query performance issues — real DB catches more real-world bugs.
Unit testing: tests a single function/class in isolation, mocks all external dependencies — fast (< 1 ms), stable, easy to debug when it fails (you know exactly where the problem is), requires no external services.
- Best for: algorithms, business logic, pure functions, utilities.
- Integration testing: tests interactions between multiple components/services with real or minimally mocked dependencies — for example, testing an API handler with a real database (test container), or a service with a real HTTP client.
- Slower (100 ms – 1 s), catches bugs at boundaries (schema mismatches, query errors, API contract violations) that unit tests cannot.
- Supertest pattern (Node.js): const app = express(); const response = await request(app).get('/api/users').expect(200) — tests Express routes with the real middleware stack, only mocking external services.
- Test containers: spin up real PostgreSQL/Redis in Docker for tests — deterministic, isolated, cleaned up after tests.
- Contract tests replace integration tests in microservices when services are owned by different teams.
- Testing Library philosophy: 'The more your tests resemble the way your software is used, the more confidence they can give you' — integration tests typically provide more confidence per test than unit tests.
- Mock database vs real database: mocks are faster but may miss SQL syntax errors, constraint violations, and query performance issues — a real DB catches more real-world bugs.