SpringSecurity를 사용하는 프로젝트에서 만약 Contrller의 단위 테스트 작업을 진행할 경우, 사용자의 인증정보가 필요하게 될 것이다. 해당 인증정보를 어떻게 Mocking하는지에 대해서 알아보자
문제원인
- MockMvc로 Controller Layer 단위 테스트시에 SpringSecurity가 활성화된 상태에서 MockMvc.perform() 호출 시 인증 정보가 주입되지 않으면 기본적으로 403 Forbidden 오류가 발생한다.
- TestingAuthenticationToken 이나 커스텀 토큰으로 인증 객체 생성시에 필요한 권한 정보가 설정되지 않으면 Security 인가 과정이 실패한다.
해결 방안
- @WithMockUser 또는 SecurityMockMvcRequestPostProcessors 사용
@Test
@WithMockUser(username = "testUser", roles = {"USER"})
void testController_withMockUser() throws Exception {
mockMvc.perform(get("/v3/api/me/playtime")
.param("year", "2025"))
.andExpect(status().isOk())
.andExpect(jsonPath("$", hasSize(1)))
.andExpect(jsonPath("$[0].totalPlayTime").value("8760시간 0분"))
.andExpect(jsonPath("$[0].totalParticipant").value(50))
.andExpect(jsonPath("$[0].totalFollowers").value(0))
.andDo(print());
}
테스트 메서드에 @WithMockUser(username = "testUser", roles = {"USER"}) 해당 기능을 사용하면 기본값으로 사용자 이름과 권한을 가진 인증 객체를 생성한다
2. SecurityMockMvcRequestPostProcessors 사용하기
mockMvc.perform(get("/v3/api/me/playtime")
.param("year", String.valueOf(year))
.with(authentication(new TestingAuthenticationToken(dummyUser, null, "ROLE_USER"))))
.andExpect(status().isOk())
.andExpect(jsonPath("$", hasSize(1)))
.andExpect(jsonPath("$[0].totalPlayTime").value("8760시간 0분"))
.andExpect(jsonPath("$[0].totalParticipant").value(50))
.andExpect(jsonPath("$[0].totalFollowers").value(0))
.andDo(print());
- TestingAuthenticationToken에 권한 추가하기
import org.springframework.security.authentication.TestingAuthenticationToken;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
@Test
void testController_withTestingAuthenticationToken() throws Exception {
TestingAuthenticationToken dummyUser = new TestingAuthenticationToken("testUser", null, "ROLE_USER");
mockMvc.perform(get("/v3/api/me/playtime")
.param("year", "2025")
.with(authentication(dummyUser)))
.andExpect(status().isOk())
.andExpect(jsonPath("$", hasSize(1)))
.andExpect(jsonPath("$[0].totalPlayTime").value("8760시간 0분"))
.andExpect(jsonPath("$[0].totalParticipant").value(50))
.andExpect(jsonPath("$[0].totalFollowers").value(0))
.andDo(print());
}
Spring Security의 TestingAuthenticationToken을 사용하여 인증 객체를 직접 생성하고 권한을 추가할 수 있다.
학습 포인트
- MockMvc와 Spring Security의 연동
- MockMvc로 Controller를 테스트 때도 SpringSecurity 필터 체인이 동작한다는 점을 이해해야한다.
- 인증이 필요한 API라면 반드시 Mock 또는 실제 인증과정을 시뮬레이션 해야 테스트가 성공한다.
- 테스트 인증 방법의 다양성
- @WithMockUser, .with(user(...)), TestingAuthenticationToken 등 다양한 방법이 존재한다.
- 상황에 따라 원하는 사용자 정보(이메일, 권한, roles 등)를 세부적으로 설정할 수 있다.
- 프로덕션 환경 vs 테스트 환경 구분
- 실제 배포 환경에서는 OAuth2, JWT, 세션 등 다양한 방식으로 인증이 이루어진다.
- 하지만 테스트 시에는 인증 로직을 간소화 하거나 Mock을 사용해, Controller나 Service 로직 검증에 집중하는 것이 중요하다.
- 필요하다면 Spring Security Test 라이브러리가 제공하는 전용 애노테이션(@WithMockUser, @WithSecurityContext)또는 SecurityMockMvcRequestPostProcessors를 적극 활용할 수 있다.
'프로젝트 이슈 및 몰랐던점 정리 > CommunityAPI' 카테고리의 다른 글
[학습 포인트] 💡Redis를 활용한 toggle(좋아요)기능 구현하기 (0) | 2025.03.30 |
---|---|
[학습 포인트] 💡Mockito Matchers와 실제 값을 이용한 테스트의 차이 (0) | 2025.03.30 |
[학습 포인트] 💡Redis 단위 테스트 작성하기 feat.ValueOperations, Operations (0) | 2025.03.30 |
[트러블 슈팅] ⚠️A component required a bean named 에러 원인 (0) | 2025.03.30 |
[트러블 슈팅] ⚠️ 읽기 전용 트랜잭션 내 쓰기 작업 문제와 REQUIRES_NEW 전파 전략 활용 (0) | 2025.03.30 |