📌 목표
- 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