Skip to main content

Command Palette

Search for a command to run...

테스트 더블 (Test Double)

Published
3 min readView as Markdown
테스트 더블 (Test Double)

테스트 더블(Test Double)xUnit Test Patterns의 저자 Gerard Meszaros가 만든 용어로,

소프트웨어 테스트에서 실제 객체를 대체하는 가짜 객체를 통칭하는 개념입니다.

실제 DB나 외부 API와 상호작용하는 코드는 테스트하기 무겁고 제어하기 어렵기 때문에,

테스트 더블을 사용해 테스트를 독립적이고 빠르게 만들 수 있습니다.


테스트 더블이 필요한 이유

  • 실제 환경 의존성 제거: DB, 네트워크, 외부 API 없이 테스트 가능

  • 테스트 속도 향상: 인메모리 객체 사용으로 I/O 부담 감소

  • 예측 가능한 테스트: 외부 서비스 상태와 무관하게 결과 고정

  • 특정 상황 시뮬레이션: 에러/타임아웃 등 비정상 케이스 재현 가능


테스트 더블의 종류 (Gerard Meszaros 분류)

1️⃣ Dummy

인스턴스는 필요하지만 동작은 전혀 필요 없는 객체

  • 파라미터를 채우기 위해서만 사용되고, 실제 로직에서는 쓰이지 않음

  • 호출되어도 정상 동작 보장하지 않음


class NotificationService {
    public void sendNotification(User user) {
        // 테스트에서 user는 사용되지 않음
    }
}

@Test
void dummyTest() {
    NotificationService service = new NotificationService();
    User dummyUser = new User(); // 아무 동작 없는 더미 객체
    service.sendNotification(dummyUser);
}

사용 포인트: 단순히 객체만 필요할 때


2️⃣ Fake

실제와 유사하게 동작하지만 단순화된 구현

  • 동작은 하지만 프로덕션 환경에서는 적합하지 않음

  • 예: 인메모리 DB, 메모리 기반 Repository


interface UserRepository {
    User save(User user);
    Optional<User> findById(Long id);
}

// 인메모리 Fake 구현
class FakeUserRepository implements UserRepository {
    private final Map<Long, User> store = new HashMap<>();
    public User save(User user) { store.put(user.getId(), user); return user; }
    public Optional<User> findById(Long id) { return Optional.ofNullable(store.get(id)); }
}

@Test
void fakeTest() {
    UserRepository repo = new FakeUserRepository();
    repo.save(new User(1L, "홍길동"));
    assertTrue(repo.findById(1L).isPresent());
}

사용 포인트: DB 없이 빠른 테스트를 하고 싶을 때


3️⃣ Stub

고정된 값을 반환하는 테스트용 구현

  • 외부 API나 Repository 호출 결과를 항상 같은 값으로 응답하게 함

  • 테스트를 예측 가능하고 안정적으로 만듦


public class StubUserRepository implements UserRepository {
    // ...
    @Override
    public User findById(long id) {
        return new User(id, "Test User");
    }  // 동일한 id 값에 Test User라는 값을 가진 고정된 User 인스턴스 반환받음
}

사용 포인트: 특정 값으로 테스트를 고정하고 싶을 때


4️⃣ Mock

행위(Behavior) 검증을 위한 객체

  • 메서드가 올바르게 호출됐는지(횟수/인자) 검증

  • verify()로 호출 여부를 체크 → 결과값이 아니라 행위 자체를 테스트


@ExtendWith(MockitoExtension.class)
class OrderServiceTest {

    @Mock PaymentGateway paymentGateway; // Mock 객체
    @InjectMocks OrderService orderService;

    @Test
    void mockTest() {
        orderService.placeOrder(500);
        // pay() 메서드가 정확히 한 번 호출됐는지 검증
        verify(paymentGateway, times(1)).pay(anyInt());
    }
}

사용 포인트: 특정 메서드가 기대한 대로 호출됐는지 확인할 때


5️⃣ Spy

Stub + 호출 기록을 남기는 객체

  • Stub처럼 값도 반환하면서, 메서드 호출 횟수나 인자를 기록

  • 테스트 종료 후 검증에 활용


class SpyEmailService implements EmailService {
    private int sendCount = 0;

    public void send(String to, String message) {
        sendCount++;
    }
    public int getSendCount() { return sendCount; }
}

@Test
void spyTest() {
    SpyEmailService spy = new SpyEmailService();
    UserService service = new UserService(spy);

    service.registerUser("test@test.com");

    assertEquals(1, spy.getSendCount()); // 호출 횟수 검증
}

사용 포인트: 호출 내역(횟수, 인자)을 검증하고 싶을 때


요약

종류특징사용 예시
Dummy동작 없음, 인스턴스만 필요파라미터 채우기
Fake단순화된 실제 구현인메모리 DB
Stub고정된 응답 반환외부 API 대체
Mock행위 검증verify()로 호출 여부 체크
SpyStub + 호출 기록호출 횟수 검증

한 줄 요약

테스트 더블은 실제 객체 대신 사용하는 가짜 객체이며, 테스트의 독립성과 안정성을 높이기 위해 사용됩니다.

목적에 따라 Dummy, Fake, Stub, Mock, Spy로 나뉘며, 각기 다른 테스트 시나리오에서 활용됩니다.

출처:https://tecoble.techcourse.co.kr/post/2020-09-19-what-is-test-double/

More from this blog

낙관적 락(Optimistic Lock)과 비관적 락(Pessimistic Lock)

락(Lock)의 필요성 현대 애플리케이션은 대부분 동시성(Concurrency) 문제에 직면합니다. 여러 사용자나 프로세스가 동시에 같은 데이터를 수정하거나, 은행 계좌 이체와 같은 중요한 트랙잭션을 동시에 실행하는 경우가 있습니다. 이때 동시 접근을 적절히 제어하지 않으면, 데이터 불일치, 중복 처리, 시스템 오류까지 발생할 수 있습니다. 이를 방지하기 위해 락(Lock) 개념이 도입되었습니다. 락은 여러 프로세스나 스레드가 동시에 동일한 자...

Aug 22, 20253 min read

Java 프로그램이 실행되는 흐름

자바 프로그램은 단순히 .java 파일을 실행하는 것이 아니라, 컴파일 → 로드 → 실행 이라는 여러 단계를 거쳐 최종적으로 CPU 가 이해할 수 있는 기계어로 변환됩니다. 이 과정에서 JDK, JVM, JRE가 각각 어떤 역할을 하는지 이해하는 것이 중요합니다. 1. 소스 코드 작성과 컴파일 개발자는 자바 소스 파일(.java)을 작성 JDK 에 포함된 javac (Java Compiler)가 소스 코드를 컴파일 하여 JVM이 이해할 수...

Aug 21, 20252 min read

Java Collection Framework

컬렉션 프레임워크(Collection Framework)란? 자바에서 컬렉션 프레임워크란 다수의 데이터를 쉽고 효과적으로 처리할 수 있는 표준화된 방법을 제공하는 클래스와 인터페이스 집합입니다. 즉, 데이터를 저장하는 자료구조과 데이터를 처리하는 알고리즘을 구조화하여 클래스로 구현한 것입니다. 모든 컬렉션 프레임워크는 자바의 인터페이스를 기반으로 구현됩니다. JFC(Java Collection Framework)의 도입 배경 JCF 이전에는 ...

Aug 14, 20254 min read

운영체제의 발전: 단일 프로세스에서 멀티코어까지

운영체제의 발전은 ‘CPU를 얼마나 효율적으로 활용하느냐’의 역사라고 볼 수 있습니다. 초기에는 한 번에 하나의 프로그램만 실행했지만, 점차 CPU 사용률과 사용자 경험을 높이기 위해 멀티프로그래밍, 멀티태스킹, 멀티프로세스, 멀티스레딩, 그리고 멀티코어 구조가 발전했습니다. 들어가기에 앞서 프로세스와 스레드에 대해 간단히 설명하겠습니다. 프로세스(Process) 실행 중인 프로그램으로 OS로부터 독립된 주소 공간과 자원을 할당 받음 각 ...

Aug 13, 20252 min read

Keep-Alive (HTTP Keep-Alive와 TCP Keep-Alive)

Keep-Alive는 연결(Connection)을 계속 유지하기 위한 메커니즘입니다. 네트워크에서 어떤 연결을 만들고, 요청/응답을 주고받은 후 바로 끊지 않고 일정 시간 동안 유지하면, 그 시간 안에 들어오는 추가 요청은 이미 열린 연결을 재사용할 수 있습니다. 이를 통해 매번 연결을 새로 맺는데 필요한 오버헤드(3-Way Handshake)를 줄일 수 있고, 불필요한 지연(latency)를 감소시킬 수 있습니다. 하지만 연결을 너무 오래 유...

Aug 12, 20252 min read

gaeng

22 posts