작성
·
423
-1
public class FollowControllerDocsTest extends RestDocsSupport {
private FollowService followService = mock(FollowService.class);
@Override
protected Object initController() {
return new FollowController(followService);
}
private final Long loginUserId = 1L;
@DisplayName("팔로우 수행 API")
@WithUserDetails
@Test
public void startFollow() throws Exception {
// Given
StartFollowRequestDto requestDto = StartFollowRequestDto.builder()
.followerId(loginUserId)
.followingId(123L)
.build();
BDDMockito.doReturn(StartFollowResponseDto.success())
.when(followService)
.follow(any(StartFollowRequestDto.class));
//when,then
mockMvc.perform(
post("/api/follow/start-follow")
.with(csrf())
.content(objectMapper.writeValueAsString(requestDto))
.contentType(MediaType.APPLICATION_JSON)
)
.andExpect(status().isOk())
.andDo(document("start-follow",
preprocessRequest(prettyPrint()),
preprocessResponse(prettyPrint()),
requestFields(
fieldWithPath("followerId").type(JsonFieldType.STRING)
.optional()
.description("팔로워 아이디"),
fieldWithPath("followingId").type(JsonFieldType.STRING)
.optional()
.description("팔로잉 아이디")
),
responseFields(
fieldWithPath("code").type(JsonFieldType.STRING)
.description(ResponseCode.SUCCESS),
fieldWithPath("message").type(JsonFieldType.STRING)
.description(SUCCESS)
)
));
}
}
FollowController
@RestController
@RequestMapping("/api/follow")
@RequiredArgsConstructor
public class FollowController {
private final FollowService followService;
@PostMapping("/start-follow")
ResponseEntity<? super StartFollowResponseDto> startFollow(
@RequestBody @Valid StartFollowRequestDto requestBody,
@AuthenticationPrincipal PrincipalDetails principalDetails
) {
Long loginId = principalDetails.getUser().getId();
Long userId = requestBody.getFollowerId();
if (loginId != userId) return StartFollowResponseDto.certificationFail();
ResponseEntity<? super StartFollowResponseDto> response = followService.follow(requestBody);
return response;
}
}
RestDocsSupport
@ExtendWith(RestDocumentationExtension.class)
public abstract class RestDocsSupport {
protected MockMvc mockMvc;
protected ObjectMapper objectMapper = new ObjectMapper();
private final Long loginUserId = 1L;
@BeforeEach
void setUp(RestDocumentationContextProvider provider) {
User user = mock(User.class);
when(user.getId()).thenReturn(loginUserId);
PrincipalDetails userDetails = mock(PrincipalDetails.class);
when(userDetails.getUser()).thenReturn(user);
SecurityContext context = SecurityContextHolder.getContext();
context.setAuthentication(new UsernamePasswordAuthenticationToken(userDetails, null, null));
this.mockMvc = MockMvcBuilders
.standaloneSetup(initController())
.apply(MockMvcRestDocumentation.documentationConfiguration(provider))
.build();
System.out.println("beforeEach 수행");
}
protected abstract Object initController();
}
안녕하세요. 강의 정말 유익하게 잘 듣고있습니다. 강의를 듣고 restdocs를 작성하던 중 문제가 발생하여 질문을 올립니다.
제가 작성한 controller에서는 파라미터로 security.context 안에 있는 PrincipalDetails를 받아옵니다.
그렇지만 테스트에선 그 안에 값이 있는게 아니여서 Mock값을 넣어주어 @WebMvcTest 에서는 문제를 해결해 왔었습니다.
문제는 restdocs를 작성하기 위한 테스트 코드에서 발생하였습니다. 이 테스트 코드에는 제가 적용한 PrincipalDetails 몫 이 넣어지지 않는 문제가 있었습니다.
제가 생각하기론 SpringSecurity가 올라가지 않아서 그런 것 같은데 해결방법이 있으면 알고싶습니다 !
답변 2
0
안녕하세요, 김승수 님!
질문 주신 내용에 대해 제가 하나하나 알려드리기 보다는, Security와 관련해서 테스트를 할 때에 대표적으로 많이 사용하는 @WithMockUser
어노테이션 등에 대해서 한번 찾아보고 적용해보시기를 권합니다. ㅎㅎ
추가로 남겨주신 질문에 대해서,
@WebMvcTest 에 @AutoConfigureRestDocs 을 붙여서 하고 있는데 이렇게 해도 상관없는지
네, 상관 없습니다.
validation exception 이 발생하는 api 테스트도 문서로 작성을 모두 해야하는지
해야 한다기 보다는 여유가 된다면 하면 좋은 것이겠죠?
내가 만든 API, 우리 팀이 제공하는 API를 외부 팀에게 어느 수준까지 정보를 제공해주면 좋을지 고민해보고 결정하면 될 문제 같습니다. ㅎㅎ
감사합니다 🙂
0
아 그리고 !지금은 @WebMvcTest 에 @AutoConfigureRestDocs 을 붙여서 하고 있는데 이렇게 해도 상관없는지도 알고싶습니다 ! 추가로 validation exception 이 발생하는 api 테스트도 문서로 작성을 모두 해야하는지 궁금합니다.!
답변 감사합니다!!