테스트 코드를 왜 써야하는가
잘못된 인식
- 테스트 = 귀찮은 추가 작업
- 테스트 = 커버리지 숫자 맞추기
- 테스트 = 모든 메서드에 assert 붙이기
올바른 인식
- 테스트는 설계의 결과물
- 테스트는 의도를 문서화하는 코드
- 테스트는 미래의 나(또는 팀원)를 살리는 보험
=> 테스트가 쓰기 어렵다면, 설계가 잘못된 경우가 많다
테스트는 책임 단위로 작성
예시:
- UserService
- 모든 기능 다 테스트
- 회원 가입 규칙을 올바르게 처리하는가?
즉, 테스트 이름만 봐도 이 코드는 무엇을 책임지는지 보여야 한다.
주의할점
Controller 테스트는 Service를 신뢰해야 한다
Service 동작까지 검증하면 중복 테스트 + 책임 침범으로 본다
따라서 약속된 HTTP 상태 코드가 내려오는지만 검증한다
정상 흐름 vs 예외 흐름
| 구분 | 설명 |
| Happy Path | 정상 입력 → 정상 결과 |
| Edge Case | 경계값, null, 빈 값 |
| Error Case | 예외 발생, 잘못된 요청 |
정상 흐름이란 : 시스템이 기대하는 조건을 모두 만족했을 때, 의도한 결과가 나오는 경로
@Test
void 회원가입이_정상적으로_성공한다() {
// given
SignupRequest req = validRequest();
// when
User user = authService.signup(req);
// then
assertThat(user.getId()).isNotNull();
}
이 테스트의 역할
- 기본 기능이 살아있는지 확인
- 리팩토링 후 “최소한 이건 깨지지 않았는지” 보장
하지만 이것만 있으면 테스트의 30%만 한 것이다.
예외 흐름이란:
현실의 입력은 대부분 “정상”이 아님을 생각해야한다.
사용자가 잘못된 값을 입력하거나 네트워크 상태가 끊긴다거나 등.. 이러한 잘못된 상황을 막는것이 백엔드가 해야할일!
예외 흐름 종류 1 - 검증 실패
입력값 자체가 잘못된 경우를 말한다
- 이메일 형식 오류
- 비밀번호 길이 부족
예외 흐름 종류 2 - 상태 기반 예외
입력은 정상인데, 현재 상태가 허용하지 않는 경우를 말한다
- 이미 탈퇴한 유저
- 이미 결제 완료된 주문
예외 흐름 종류 3 - 상태 기반 예외
외부 요인, 인프라 문제를 말한다.
- DB저장 실패시 회원가입 롤백되는가
- 외부 API 장애
이 테스트는 “왜 존재하는가?”
모든 테스트는 질문 하나에 답해야 한다.
“이 테스트가 없으면 어떤 버그를 못 잡을까?”
이 질문에 답 못 하면 의미 없는 테스트일 확률이 높다
Mock을 쓴다는 것의 진짜 의미
Mock은 “편의”가 아니라 “경계 설정”이다
Mock을 쓴다는 말은 곧:
“나는 이 객체의 내부 구현이 아니라, 역할만 신뢰한다”
예시:
- Service 테스트에서
- Repository는 Mock
- 이유: DB 검증이 목적이 아니기 때문
Mock 남용 = 테스트 신뢰도 하락
Mock 부족 = 테스트가 느리고 불안정
테스트는 설계 리뷰 도구다
| 테스트 작성 중 느끼는 감정 | 의미 |
| 세팅이 너무 길다 | 책임이 많다 |
| Mock이 너무 많다 | 결합도가 높다 |
| 테스트 이름 짓기 어렵다 | 역할이 모호하다 |
| private 메서드 테스트하고 싶다 | 구조가 잘못됐다 |
JSON
json <->Dto 변환시
json에서는 권한을 string으로 전달하더라도
자바 dto에서는 이를 enum타입으로 명시했다면 자동으로 변환해준다
그렇다면 테스트에서 dto-> json으로 변환하는 과정을 거치는 이유가 무엇일까?
1.dto를 수정했을 때 런타임이 아닌 컴파일 단에서 에러를 잡을 수 있다
2.json으로 작성했을 경우 까먹고 넘어갈 수 있다
테스트는 통과할 수도 있음 (실제 API는 깨짐)
mockMvc: 가짜 HTTP 요청 보내기
- 실제 서버를 띄우지 않고
- Spring MVC DispatcherServlet까지만 실행하는 테스트 도구
mockMvc.perform(post("/api/auth/signup")
HTTP 헤더 설정
Spring은 이걸 보고:
- @RequestBody를 무엇으로 파싱할지 결정
- 여기선 JSON으로 파싱
.contentType(MediaType.APPLICATION_JSON)
DTO 객체 → JSON 문자열 변환 후 HTTP Body에 JSON을 담음
.content(objectMapper.writeValueAsString(signupReqDto)))
http 요청 결과 형태
POST /api/signup
Content-Type: application/json
{
"email": "test@test.com",
"password": "password123",
"role": "BUYER"
}
@MockBean
Spring Boot 3.4.0 버전부터 @MockBean Deprecated
@MockitoBean으로 대체
엄청나게 긴 오류코드를 마주했다 한줄씩 해석해보자
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.example.yongeunmarket.jwt.JwtFilter required
a bean of type 'com.example.yongeunmarket.jwt.JwtTokenProvider' that could not be found.
2025-12-19T17:42:45.669+09:00 WARN 2960 --- [yongeun-market] [ Test worker] o.s.test.context.TestContextManager : Caught exception while allowing TestExecutionListener [org.springframework.test.context.bean.override.BeanOverrideTestExecutionListener] to prepare test instance [com.example.yongeunmarket.controller.AuthControllerTest@5db0003d]
java.lang.IllegalStateException: Failed to load ApplicationContext for
[WebMergedContextConfiguration ...
org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTestContextBootstrapper=true]
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'jwtFilter' defined in file [/Users/heoarim/sparta/consumer-to-consumer-project/build/classes/java/main/com/example/yongeunmarket/jwt/JwtFilter.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'com.example.yongeunmarket.jwt.JwtTokenProvider' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:804) ~[spring-beans-6.2.14.jar:6.2.14]
... 생략
- JwtFilter 클래스가 문제다 JwtTokenProvider 주입받으려다 실패했다 왜? Bean이 없다
- 스프링의 핵심 컨테이너인 ApplicationContext를 로드하는데 실패했다
여기서 알아야할 것은 컨트롤러 테스트를 하고있는데 스프링을 띄우다가 실패했다는 것이다.
'TIL' 카테고리의 다른 글
| TIL/ 260112 (0) | 2026.01.13 |
|---|---|
| TIL/251222 (0) | 2025.12.22 |
| TIL/ 연관관계 매핑 (0) | 2025.10.21 |
| TIL / RESTful API (0) | 2025.10.17 |