- 각각의 테스트 메서드는 독립적으로 동작해야 합니다.
- 테스트는 외부 환경(API, DB, 파일 등)에 영향을 받지 않아야 합니다.
- 실행 순서와 무관하게 항상 같은 결과가 나와야 합니다.
| 종류 | 설명 | 예시 |
|---|---|---|
| Stub | 미리 정해진 값을 반환하는 객체 | 단순한 값을 리턴하게 만듬 |
| Fake | 단순한 로직이 포함된 실제 동작 객체 | 메모리 리포지토리 |
| Spy | 메서드 호출 여부/횟수 등을 검증 | 이메일 발송 기능 검증 |
| Mock | 행위 기반 검증 객체 (과도한 사용은 지양) | 스텁이자 스파이일 수 있으며 mockito 사용 |
💡 모의 객체(Mock)는 최소한으로 사용하고, 가능한 경우 Stub, Fake, Spy로 대체하세요. mock 관련 코드가 너무 많아지면 테스트 코드 유지보수가 힘듬
| 문제 상황 | 해결 방법 |
|---|---|
| 의존 객체를 직접 생성 | → DI(의존성 주입)으로 외부에서 주입 |
실행 시점에 따라 결과가 달라지는 코드 (now()) |
→ 시간 생성 로직을 별도 Clock/Provider로 분리 |
| 하나의 클래스/메서드에 여러 책임이 섞인 경우 | → 단일 책임 원칙(SRP)을 적용해 기능 분리 |
| 외부 라이브러리에 직접 의존 | → Adapter 또는 Wrapper 로 감싸서 사용 |
- 파일 저장 경로 같은 것들을 말합니다.
- 시간은 테스트 결과에 영향을 미치는 요소이므로
now()등의 직접 호출은 지양합니다. - 대신
Clock또는TimeProvider를 통해 시간 주입을 구성합니다. - 임의 값을 구하는 것도 분리합니다.
- 외부 시스템은 xxxClient 인터페이스로 추상화하여 테스트 시 목/스텁으로 대체합니다.
- 영속성 로직은 xxxRepository 인터페이스로 추상화하고, 구현은 JPA 등을 사용합니다. 테스트 시에는 메모리FakeRepository로 대체합니다.
- 특히 특정 라이브러리의 정적메서드 사용시에 감싸서 사용해야 테스트가 가능하다.
- 대역을 쓰고 싶은 클래스에 final 때매 상속이 막힌 경우에도 이 방법으로 테스트 가능하게 만들 수 있다.
- 대상: 개별 클래스나 메서드 같은 작은 단위의 컴포넌트
- 특징:
- 외부 의존성은
Mock,Stub등의 대역을 적극 활용 - 가장 많이 작성해야 하며, 다양한 세부 로직을 빠짐없이 검증
- 외부 의존성은
- 목적: 내부 로직의 정확성을 보장
- 대상: 여러 컴포넌트를 통합한 시스템 (예: 웹 애플리케이션과 데이터베이스)
- 특징:
- 실제 데이터베이스와의 연동을 포함
- 외부 API 등 외부 시스템에는 대역 사용
- 목적: 컴포넌트 간의 연동 및 전체 시스템 흐름을 검증
- 대상: 실제 사용자 시나리오 전체 흐름
- 특징:
- 사용자와 동일한 방식으로 시스템을 사용해 테스트
- 모든 구성 요소가 함께 동작하는 주요 시나리오 중심
- 작성과 실행이 복잡하고 시간이 많이 소요됨
- 목적: 사용자 관점에서 시스템이 의도대로 작동하는지 검증