📌 목표
- JWT 인증이 필요한 API (
POST /s/api/board
)를 테스트
- 로그인 토큰이 필요하기 때문에 테스트에 accessToken을 설정해야 함
- 매번 토큰 생성 코드를 작성하는 불편함 →
@BeforeEach
로 공통 초기화 처리
🧪 1. 변경 전 테스트 코드 흐름
👇 테스트 내에서 직접 accessToken을 생성
@Test public void save_test() throws Exception { // given (가짜 데이터) BoardRequest.SaveDTO reqDTO = new BoardRequest.SaveDTO(); reqDTO.setTitle("제목1"); reqDTO.setContent("내용1"); reqDTO.setPublic(true); String requestBody = om.writeValueAsString(reqDTO); // when (테스트 실행) User ssar = User.builder().id(1).username("ssar").build(); // 👈 직접 생성 accessToken = JwtUtil.create(ssar); // 👈 직접 발급 ResultActions actions = mvc.perform( MockMvcRequestBuilders .post("/s/api/board") .header("Authorization", "Bearer " + accessToken) .content(requestBody) .contentType(MediaType.APPLICATION_JSON) ); // eye String responseBody = actions.andReturn().getResponse().getContentAsString(); System.out.println(responseBody); // then actions.andExpect(MockMvcResultMatchers.jsonPath("$.status").value(200)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.msg").value("성공")); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.title").value("제목1")); }
🔍 문제점
- 매 테스트마다
User
,accessToken
생성 코드가 반복됨
- 테스트 메서드가 지저분하고 길어짐
- 테스트 목적이 흐려짐 (인증 관련 코드 vs 테스트 본래 목적이 섞임)
🔄 2. 변경 후 (BeforeEach로 리팩토링)
✅ 공통 토큰 생성 로직을 @BeforeEach
에 작성
@AutoConfigureMockMvc @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) public class BoardControllerTest { @Autowired private MockMvc mvc; @Autowired private ObjectMapper om; private String accessToken; // 테스트마다 재사용할 변수 @BeforeEach public void setup() { // ✅ 테스트 시작 전 실행 System.out.println("setup"); User ssar = User.builder().id(1).username("ssar").build(); // 가짜 유저 accessToken = JwtUtil.create(ssar); // JWT 발급 } @AfterEach public void tearDown() { // ✅ 테스트 후 정리 작업 System.out.println("tear down"); } @Test public void save_test() throws Exception { // given BoardRequest.SaveDTO reqDTO = new BoardRequest.SaveDTO(); reqDTO.setTitle("제목1"); reqDTO.setContent("내용1"); reqDTO.setPublic(true); String requestBody = om.writeValueAsString(reqDTO); // when ResultActions actions = mvc.perform( MockMvcRequestBuilders .post("/s/api/board") .header("Authorization", "Bearer " + accessToken) // 👈 재사용 .content(requestBody) .contentType(MediaType.APPLICATION_JSON) ); // eye String responseBody = actions.andReturn().getResponse().getContentAsString(); System.out.println(responseBody); // then actions.andExpect(MockMvcResultMatchers.jsonPath("$.status").value(200)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.msg").value("성공")); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.title").value("제목1")); } }
🔍 BeforeEach / AfterEach 설명
어노테이션 | 설명 |
@BeforeEach | 각 테스트 메서드 실행 전 호출됨공통으로 필요한 준비 작업 (예: 토큰 생성, DB 초기화 등)을 작성 |
@AfterEach | 각 테스트 메서드 실행 후 호출됨자원 해제, 로그 출력, 트랜잭션 롤백 등 정리 작업 수행 |
✅ 리팩토링 효과
- 테스트 코드 내 중복 제거
- 테스트 목적이 명확하게 분리됨
@BeforeEach
: 인증 세팅@Test
: 실제 기능 테스트
- 관리/유지보수 용이
🧠 보너스 팁
accessToken = JwtUtil.create(...)
는 대부분의 테스트에서 공통되므로, 이 방식은 대부분의 JWT 기반 API 테스트에 적용 가능
- 인증 테스트 시 토큰 없이 요청하여
401 Unauthorized
반환 확인도 가능
@Transactional
이 붙은 테스트는 실행 후 자동 롤백되므로, 테스트 간 데이터 충돌이 적음
🧩 [번외] 날짜 필드 createdAt
정규식 검증
✅ 왜 정규식을 사용하는가?
createdAt
필드는 보통 시스템이 자동 생성하는 날짜/시간 값입니다.이 값은 테스트 실행 시마다 매번 다르게 생성되므로, 정확한 문자열 값을
value("2025-05-13 15:46:14.216746")
처럼 비교할 수 없습니다.→ 따라서 "형식(패턴)"만 맞는지 확인하기 위해 정규식(Regex) 검증을 사용합니다.
🔤 코드 예시
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.createdAt") .value(Matchers.matchesPattern("^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d+$")));
🔍 코드 해석
📍 $.body.createdAt
- JSON 응답 중
body
객체 안에 있는createdAt
필드를 의미
📍 Matchers.matchesPattern(...)
- 해당 값이 정규식 패턴과 일치하는지 확인
📍 정규식 설명
^ // 문자열의 시작 \d{4} // 연도: 숫자 4자리 (예: 2025) - // 하이픈 \d{2} // 월: 숫자 2자리 (예: 05) - // 하이픈 \d{2} // 일: 숫자 2자리 (예: 13) \s // 공백 \d{2} // 시: 숫자 2자리 (예: 15) : // 콜론 \d{2} // 분: 숫자 2자리 (예: 46) : // 콜론 \d{2} // 초: 숫자 2자리 (예: 14) \. // 점 (소수점 앞뒤 구분) \d+ // 밀리초 또는 마이크로초 (숫자 여러 자리) $ // 문자열의 끝
✅ 예시로 통과되는 날짜 문자열
2025-05-13 15:46:14.216746
💡 정규식을 쓰는 이유 요약
이유 | 설명 |
✔ 실행마다 값이 달라짐 | createdAt 은 테스트할 때마다 시간이 달라지므로 고정값 비교가 불가능 |
✔ 형식만 검증하면 충분 | 날짜가 예상된 **형식(패턴)**에 맞는지만 확인하면 신뢰할 수 있음 |
✔ 유지보수 용이 | 테스트 깨질 확률 ↓, 불필요한 테스트 수정 방지 ↑ |
🧪 응용 예시
- 이메일 형식 검증:
^[\\w._%+-]+@[\\w.-]+\\.[a-zA-Z]{2,}$
- 핸드폰 번호 검증:
^010-\\d{4}-\\d{4}$
- UUID 형식:
^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$
Share article