테스트 더블(Test Doubles)은 테스트에서 실제 의존성을 대체하는 가짜 객체들의 총칭이다. Gerard Meszaros가 정의했으며 Dummy, Stub, Fake, Spy, Mock 5종류로 분류된다.
5가지 종류
| 종류 | 정의 | 검증 여부 |
|---|
| Dummy | 전달만 하고 사용 안 됨 | X |
| Stub | 미리 정의된 응답 반환 | X |
| Fake | 실제 동작하지만 간소화 | X |
| Spy | 실제 실행 + 호출 기록 | △ |
| Mock | 기대값 사전 설정 + 자동 검증 | O |
typescript
// 테스트 대상
class OrderService {
constructor(
private emailSvc: EmailService,
private db: OrderRepository
) {}
async placeOrder(order: Order) {
const saved = await this.db.save(order);
await this.emailSvc.send(order.userId, 'Order placed');
return saved;
}
}
// STUB: db.save 가 항상 성공 응답
const stubDb = { save: jest.fn().mockResolvedValue({ id: 1, ...order }) };
// MOCK: emailSvc 호출 검증
const mockEmail = { send: jest.fn().mockResolvedValue(undefined) };
// SPY: 실제 구현 유지하되 호출 추적
const spy = jest.spyOn(realEmailSvc, 'send');
// FAKE: 메모리 내 DB 구현
class InMemoryOrderRepo implements OrderRepository {
private store = new Map<number, Order>();
async save(o: Order) { this.store.set(o.id, o); return o; }
async findById(id: number) { return this.store.get(id) ?? null; }
}
// 테스트
it('places order and sends email', async () => {
const svc = new OrderService(mockEmail, stubDb);
await svc.placeOrder({ userId: 1, items: [] });
expect(mockEmail.send).toHaveBeenCalledWith(1, 'Order placed');
expect(mockEmail.send).toHaveBeenCalledTimes(1);
});
사용 기준
Stub 선택: 특정 반환값이 필요할 때 (DB, API)
Mock 선택: 호출 여부/횟수/인자를 검증해야 할 때
Fake 선택: 여러 테스트에서 상태 공유가 필요할 때
Spy 선택: 실제 동작을 유지하며 부수효과 확인
Dummy 선택: 파라미터 채우기용 (사용 안 됨)
고전파 vs 런던파
고전파 (Chicago): 실제 객체 선호, Fake/인메모리 사용
→ "작동하는 코드"에 초점
런던파: Mock 적극 사용, 의존성 완전 격리
→ "상호작용 올바름"에 초점
실용적 접근: 느리거나 불안정한 의존성(DB, 외부 API)만 더블
관련 문서