반응형
@WebMvcTest 어노테이션을 사용한 테스트 코드 작성
1. UserControllerTest
@ExtendWith(SpringExtension.class)
@WebMvcTest(controllers = UserController.class)
class UserControllerTest {
@Autowired
private MockMvc mvc;
@MockBean
private UserService userService;
@Test
@DisplayName("닉네임 검증; 공백 체크")
public void testNicknameDuplicateBlank() throws Exception {
mvc.perform(get("/users/check-nickname")
.queryParam("nickname", " "))
.andExpect(status().isBadRequest())
.andDo(print());
}
}
- @MockBean을 사용해서 UserService를 주입하지 않으면 오류 발생한다. [SpringBoot] @WebMvcTest 단위 테스트시 Bean 주입 에러
- .andDo(print()) 를 통해 요청/응답 메시지 전체를 확인할 수 있다.
내가 기대한 결과
.andExpect(status().isBadRequest())
의 결과는 400이므로, 테스트가 성공적으로 수행되어야 한다.
{
"status": 400,
"errorName": "BAD_REQUEST",
"message": "Nickname only contains blank",
"code": "U002"
}
실제 결과
- 401 응답이 출력되어, 400과 다르므로 테스트가 실패한다.
MockHttpServletResponse:
Status = 401
Error message = Unauthorized
Headers = [WWW-Authenticate:"Basic realm="Realm"", X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY"]
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
오류 해결
Spring Security REST - Unit Tests fail with HttpStatusCode 401 Unauthorized
@ExtendWith(SpringExtension.class)
@WebMvcTest(controllers = UserController.class, excludeAutoConfiguration = {SecurityAutoConfiguration.class})
class UserControllerTest {
@Autowired
private MockMvc mvc;
@MockBean
private UserService userService;
@Test
@DisplayName("닉네임 검증; 공백 체크")
public void testNicknameDuplicateBlank() throws Exception {
mvc.perform(get("/users/check-nickname")
.queryParam("nickname", " "))
.andExpect(status().isBadRequest())
.andDo(print());
}
}
- @WebMvcTest 어노테이션에 exclude ... 부분을 추가하니 테스트가 성공함
- 하지만 이 부분을 추가해야하는 원인은 아직 모르겠다.
- 5/22 해당 내용과 유사한 내용의 글을 발견함. 스프링부트 JUnit5 - Error creating bean with name 'securityConfig' defined in file 해결법
2. @WebMvcTest는 Service나 Repository class를 주입받을 수 없다.
따라서 Controller만 테스트할 경우에 사용한다. 이 때, @WebMvcTest를 사용하면 MockMvc를 주입받아서 사용할 수 있다.
3. java.lang.IllegalStateException: Failed to load ApplicationContext 오류 해결
- JWT 인증 처리를 위해 JwtAuthenticationFilter를 생성한 뒤, 기존의 UserControllerTest를 실행하였으나 오류가 발생하였다.
- JwtAuthenticationFilter 및 JwtTokenProvider를 @Component를 통해 Spring Bean에 등록한 상태.
- 오류 메시지는 아래와 같다.
3-1. 오류 원인
@WebMvcTest 는 컨트롤러와 관련된 Bean을 자동으로 configuration하며, 해당 Bean들은 아래와 같다.
- @Controller
- @ControllerAdvice
- @JsonComponent
- Converter
- GenericConverter
- Filter
- HandlerInterceptor
- WebMvcConfigurer
- HandlerMethodArgumentResolver
JwtAuthenticationFilter
@Slf4j
@Component
@RequiredArgsConstructor
@Order(1)
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtTokenProvider jwtTokenProvider;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
log.info(">> Enter the JwtAuthenticationFilter");
String jwtToken = parseJwt(request);
// if (jwtToken != null && jwtTokenProvider.validateToken(jwtToken)) {
// Authentication auth = jwtTokenProvider.getAuthentication(jwtToken);
// SecurityContextHolder.getContext().setAuthentication(auth);
// }
//
// log.info("next Filter");
filterChain.doFilter(request, response);
}
private String parseJwt(HttpServletRequest request) {
String headerAuth = request.getHeader("Authorization");
if (StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")) {
return headerAuth.substring(7);
}
return null;
}
}
오류 원인은 아직 잘 모르겠다..
3-2. 해결 방법
1. JwtAuthenticationFilter에서, @Component 어노테이션 주석 처리 후 실행
@Slf4j
//@Component
@RequiredArgsConstructor
@Order(1)
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtTokenProvider jwtTokenProvider;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
// 생략
filterChain.doFilter(request, response);
}
}
2. UserControllerTest에서, excludeFilter를 통해 JwtAuthenticationFilter 제외시킴
@MockBean(JpaMetamodelMappingContext.class)
@WebMvcTest(controllers = UserController.class, excludeAutoConfiguration = {SecurityAutoConfiguration.class},
// 아래 내용 추가
excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = JwtAuthenticationFilter.class)})
@TestPropertySource(locations = "classpath:application-jwt.properties")
class UserControllerTest {
// 생략
}
반응형
'Spring Boot > Test Code' 카테고리의 다른 글
Junit5] 테스트 코드 작성을 위한 서비스 코드 리팩토링 (0) | 2023.07.14 |
---|---|
Junit5] org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false (0) | 2023.07.08 |
Junit5] NullPointerException with @Value (0) | 2023.07.02 |
Junit5] WebMvcTest: MockHttpServletResponse: Status = 401 Error message = Unauthorized (0) | 2023.07.01 |
Junit5] 테스트 코드 작성 원칙 정리 (0) | 2023.06.09 |