728x90
에러발생
TestCode를 진행하다 보니
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.NullPointerException
NullPointerException이 발생하고 있었다.
컨트롤러
@RestController
@RequestMapping("/api/v1/blog")
@RequiredArgsConstructor
public class BlogRestController {
private final BlogService blogService;
@PostMapping("/rename/{blogId}")
public Response<RenameBlogResponse> renameBlog(
@RequestBody @Valid final RenameBlogRequest request,
@PathVariable final Long blogId,
final Authentication authentication) {
String memberEmail = authentication.getName();
return Response.success(blogService.renameBlog(memberEmail, request, blogId));
}
}
테스트 코드
@WebMvcTest(BlogRestController.class)
@AutoConfigureRestDocs
@ExtendWith(RestDocumentationExtension.class)
@WithMockUser
class BlogRestControllerTest {
...
@BeforeEach
void setUp(WebApplicationContext webApplicationContext, RestDocumentationContextProvider restDocumentation) {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
.apply(documentationConfiguration(restDocumentation))
.apply(springSecurity())
.build();
}
@Test
void rename_success() throws Exception {
RenameBlogRequest request = RenameBlogRequest
.builder()
.name("수정된 블로그 이름입니다.")
.build();
RenameBlogResponse response = RenameBlogResponse
.builder()
.blogId(1L)
.blogName("수정된 블로그 이름입니다.")
.build();
long blogId = 1L;
given(blogService.renameBlog(any(), any(), any())).willReturn(response);
mockMvc.perform(post("/api/v1/blog/rename/" + blogId)
.with(csrf())
.header(HttpHeaders.AUTHORIZATION, "TOKEN")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsBytes(request)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.resultCode").value("SUCCESS"))
.andExpect(jsonPath("$.data.blogId").value(1L))
.andExpect(jsonPath("$.data.blogName").value("수정된 블로그 이름입니다."))
.andDo(print())
.andDo(document("blog/rename-success",
preprocessRequest(prettyPrint()),
preprocessResponse(prettyPrint()),
requestFields(
fieldWithPath("name").description("수정된 블로그 이름입니다.")
),
responseFields(
fieldWithPath("resultCode").description("결과 코드"),
fieldWithPath("data.blogId").description("블로그 번호"),
fieldWithPath("data.blogName").description("블로그 이름")
)));
}
}
에러의 발생 위치는 Controller 부분에서 Authentication을 사용하여 Name을 받아오는 부분이었다.
String memberEmail = authentication.getName();
위의 부분이 Null로 잡혀서 에러가 계속 발생하고 있었다.
문제해결
BeforeEach내부에서 springSecurity()를 추가하면 문제는 해결된다.
@BeforeEach
void setUp(WebApplicationContext webApplicationContext, RestDocumentationContextProvider restDocumentation) {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
.apply(documentationConfiguration(restDocumentation))
.apply(springSecurity()) // 추가
.build();
}
springSecurity()를 타고 들어가게 되면 다음과 같이 적혀있다.
/**
* Configures the MockMvcBuilder for use with Spring Security. Specifically the
* configurer adds the Spring Bean named "springSecurityFilterChain" as a Filter. It
* will also ensure that the TestSecurityContextHolder is leveraged for each request
* by applying
* {@link org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors#testSecurityContext()}
* .
* @return the {@link org.springframework.test.web.servlet.setup.MockMvcConfigurer} to
* use
*/
public static MockMvcConfigurer springSecurity() {
return new SecurityMockMvcConfigurer();
}
스프링 시큐리티를 사용하기 위한 MockMvcBuilder를 설정합니다.
특히 설정하는 사람은 "springSecurityFilterChain"라 불리는 스프링빈을 필터로 추가합니다.
또한 TestSecurityContextHolder가 각 요청에 대해 사용될 수 있도록 합니다.
이유 찾기
여기서 궁금한 부분이 발생한다.
지금까지 위와 같은 apply(springSecurity())를 추가하지 않고도 테스트 코드가 잘 돌아갔는데, 갑자기 이러한 에러가 발생하는 이유는 뭘까?
@BeforeEach
void setUp(WebApplicationContext webApplicationContext, RestDocumentationContextProvider restDocumentation) {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
.apply(documentationConfiguration(restDocumentation))
.apply(springSecurity()) // 추가
.build();
}
문제는 mockMvc를 MockMvcBuilders를 사용하여 새롭게 초기화되면서 발생했다
반응형