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.

The Testing Spectrum

<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>

Types of Testing

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

Unit Tests

// 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:

Integration Tests (Our Focus)

// 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:

E2E Tests