Script Valley
Reading Other People's Code
Contributing to an Existing CodebaseLesson 5.3

How to write tests for code you didn't write

testing existing behavior, characterization tests, finding test boundaries, mocking dependencies you don't own, test doubles, testing edge cases in legacy code

Test What It Does, Not What It Should Do

Characterization test workflow diagram

When writing tests for unfamiliar code, your first job isn't to test what the code should do — it's to characterize what it actually does. These are called characterization tests, and they serve as a safety net before refactoring.

Writing a Characterization Test

// You're not sure what parseDateRange does — run it and observe
const result = parseDateRange('2024-01-15', '2024-01-20');
console.log(result);
// Output: { start: Date('2024-01-15'), end: Date('2024-01-20'), days: 5 }

// Now encode what it actually does as a test
test('parseDateRange returns start, end Date objects and day count', () => {
  const result = parseDateRange('2024-01-15', '2024-01-20');
  expect(result.start).toEqual(new Date('2024-01-15'));
  expect(result.end).toEqual(new Date('2024-01-20'));
  expect(result.days).toBe(5);
});

// Also test the boundary — what happens with same-day range?
test('parseDateRange with same start and end date returns days: 0', () => {
  const result = parseDateRange('2024-01-15', '2024-01-15');
  expect(result.days).toBe(0);
});

Mocking Dependencies You Don't Own

// If the function calls a DB, mock it
jest.mock('../db/users', () => ({
  findById: jest.fn().mockResolvedValue({ id: '1', email: 'a@b.com' })
}));

Test the unit in isolation first. Integration tests verify the whole chain — write them after you understand each piece.

Up next

How to write a good pull request description for unfamiliar code

Sign in to track progress