Today I Learned
테스트 코드
#테스트 코드의 목적
테스트 코드는 단순히 “코드가 잘 동작하는지 확인”하는 것을 넘어, 코드 품질 보증과 리팩토링 안전망 역할을 한다.
- 버그 예방: 기능 변경 시 기존 기능이 깨지지 않았는지 빠르게 확인 가능
- 문서화: 테스트 자체가 코드 사용 예시가 되어, 동작 방식을 이해하는 데 도움
- 리팩토링 안전망: 구조 변경 시 기존 동작이 유지되는지 보장
#테스트의 종류
단위(Unit) 테스트
- 가장 작은 단위(메서드, 클래스)를 독립적으로 검증
- 외부 의존성(DB, 네트워크 등)은 Mocking 처리
- 예: `@Mock`, `@InjectMocks`를 사용한 Mockito 기반 테스트
통합(Integration) 테스트
- 여러 모듈이 함께 동작하는 지 검증
- 실제 DB, 외부 API, Spring Context를 로드하여 테스트
- 예: `@SpringBootTest`, `@AutoConfigureMockMvc`
인수(Acceptance) 테스트
- 사용자의 시나리오 관점에서 전체 흐름 검증
- 예: RestAssured, Selenium 등을 활용한 E2E 테스트
#단위 테스트와 통합 테스트의 차이
| 구분 | 단위 테스트 | 통합 테스트 |
| 실행 속도 | 빠름 | 느림 |
| 의존성 | 없음 (Mock 사용) | 실제 환경 사용 |
| 목적 | 로직 검증 | 모듈 간 연동 검증 |
| 예시 | Service 메서드 검증 | Controller + Service + Repository 전체 흐름 검증 |
#테스트 코드 작성 원칙 (FIRST)
Fast: 빠르게 실행되어야 한다.
Isolated: 테스트는 서로 독립적이어야 한다.
Repeatable: 환경에 상관없이 항상 같은 결과를 내야 한다.
Self-Validating: 테스트 결과는 자동으로 검증되어야 한다.
Timely: 코드 작성 시점에 맞춰 테스트도 함께 작성해야 한다.
#Mock과 Stub
Mock: 행위(메서드 호출 여부, 횟수 등)를 검증하는 가짜 객체
Stub: 미리 정해진 값을 반환하는 가짜 객체
Mockito에서는 `when(...).thenReturn(...)`으로 Stub, `verify(...)`로 Mock 검증을 수행한다.
#@Mock vs @MockBean
`@Mock`: Mockito에서 제공, Spring Context를 로드하지 않고 순수 단위 테스트에 사용
`@MockBean`: Spring Boot에서 제공, Spring Context에 Mock 객체를 등록하여 통합 테스트에서 사용
#테스트 코드 특징
하나의 테스트는 하나의 개념만 검증한다.
Given-When-Then 패턴을 따른다.
- Given: 테스트 준비
- When: 동작 실행
- Then: 결과 검증
테스트 이름은 시나리오를 설명하도록 작성한다.
- 예: `회원가입_이메일중복일때_예외발생()`
테스트 간 데이터 의존성을 만들지 않는다.
외부 API나 DB에 의존하는 테스트는 격리하거나 Mocking한다.
무조건 100% 커버리지를 목표로 하기보다, 중요 로직에 집중한다.
마치며
처음엔 테스트 코드를 “검증용 부가 작업” 정도로만 생각했는데, 프로젝트를 진행하면서 테스트가 곧 안전망이라는 걸 체감했다. 리팩토링이나 기능 추가를 할 때, 테스트가 있으면 마음이 훨씬 편하다. 버그를 사전에 잡아주고, 코드 변경이 기존 기능을 깨뜨리지 않았는지 바로 확인할 수 있다. 테스트는 개발 속도를 늦추는 게 아니라, 장기적으로는 속도를 높이는 투자라는 걸 알게 되었다.