Testing is not optional in production-ready APIs. In this lesson, we'll implement comprehensive integration tests that give us confidence our API works as expected from the client's perspective.
<aside> 🎯
Testing Philosophy
Write tests not for coverage metrics, but for confidence. Integration tests give you the most confidence per line of test code for APIs.
</aside>
Test Type | Scope | Speed | Confidence | Best For |
---|---|---|---|---|
Unit Tests | Single function/method | ⚡ Very Fast | Low | Business logic, utilities |
Integration Tests | Multiple components | 🚶 Medium | High | APIs, database operations |
E2E Tests | Entire system | 🐌 Slow | Very High | Critical user flows |
Snapshot Tests | UI components | ⚡ Fast | Medium | UI consistency |
// Tests a single function in isolation
test('hashPassword should return hashed string', () => {
const hashed = hashPassword('mypassword');
expect(hashed).not.toBe('mypassword');
expect(hashed).toMatch(/^\\$2[ayb]\\$.{56}$/);
});
Characteristics:
// Tests multiple components working together
test('POST /api/habits creates habit in database', async () => {
const response = await request(app)
.post('/api/habits')
.set('Authorization', `Bearer ${token}`)
.send({ name: 'Exercise' });
expect(response.status).toBe(201);
// Verifies it actually hit the database
expect([response.body.habit.id](<http://response.body.habit.id>)).toBeDefined();
});
Characteristics: