💡 .java를 클릭시 관련 커밋으로 이동💡
회고
// Todo 수정
@ApiResponse(responseCode = "200", description = "Todo 수정 성공")
@PutMapping("/{studyInfoId}/todo/{todoId}")
public JsonResult<?> updateStudyTodo(@AuthenticationPrincipal User user,
@PathVariable(name = "studyInfoId") Long studyInfoId,
@PathVariable(name = "todoId") Long todoId,
@Valid @RequestBody StudyTodoUpdateRequest studyTodoUpdateRequest) {
studyMemberService.isValidateStudyLeader(user, studyInfoId);
studyTodoService.updateStudyTodo(studyTodoUpdateRequest, todoId);
return JsonResult.successOf("Todo update Success");
}
@Valid: Bean Validation API의 일부로, 이 어노테이션은 요청 본문으로 받은 객체(StudyTodoUpdateRequest)의 유효성 검사를 활성화 한다.
예를 들어, StudyTodoUpdateRequest 클래스 내에는 @NotNull, @Size, @Past 등 다양한 제약 조건 어노테이션이 필드 위에 설정될 수 있는데 @Valid 어노테이션을 통해 이러한 제약 조건이 만족하는지 확인하고, 만족하지 않을 경우 유효성 검사 에러를 반환한다!
여기서 @Valid 주로 Bean Validation API를 사용하는데 Bean Validation은 자바 객체의 필드에 대한 제약 조건을 정의하고 검증할 수 있는 API이다.
예를 들어, HTTP POST 요청으로 전달되는 데이터가 유효한지 확인해야 하는 경우에 @RequestBody와 @Valid를 함께 사용할 수 있다. 이렇게 함으로써 스프링은 요청 본문의 데이터를 자바 객체로 변환하고, 변환된 객체의 유효성을 검증하여 필요한 경우에는 예외를 발생시킬 수 있다!!
→ 이점: 유효성 검증을 수행하는 이유는 잘못된 또는 부적절한 데이터가 애플리케이션으로 들어오는 것을 방지하기 위해서 👍 데이터의 유효성을 검증함으로써 애플리케이션의 안정성을 높이고, 예상치 못한 오류를 방지한다.
public void updateStudyTodo(String title, String detail, String todoLink, LocalDate todoDate) {
this.title = title;
this.detail = detail;
this.todoLink = todoLink;
this.todoDate = todoDate;
}
StudyTodo 클래스에 인스턴스 변수 업데이트(setter) 메서드 추가
// Todo 수정
@ApiResponse(responseCode = "200", description = "Todo 수정 성공")
@PutMapping("/{studyInfoId}/todo/{todoId}")
public JsonResult<?> updateStudyTodo(@AuthenticationPrincipal User user,
@PathVariable(name = "studyInfoId") Long studyInfoId,
@PathVariable(name = "todoId") Long todoId,
@Valid @RequestBody StudyTodoUpdateRequest studyTodoUpdateRequest) {
studyMemberService.isValidateStudyLeader(user, studyInfoId);
studyTodoService.updateStudyTodo(studyTodoUpdateRequest, todoId);
return JsonResult.successOf("Todo update Success");
}
Todo 수정 Controller 구현
Todo 수정역시 리더만 가능 studyMemberService.isValidateStudyLeader(user, studyInfoId);
클라이언트로부터 받은 JSON 요청 본문(Request Body)을 Java 객체로 변환하고, 이 객체에 대한 검증을 수행
@Getter
@Builder
@AllArgsConstructor
public class StudyTodoUpdateRequest {
@Size(max = 20, message = "제목 20자 이내")
private String title; // To do 이름
@Size(max = 50, message = "설명 50자 이내")
private String detail; // To do 설명
private String todoLink; // To do 링크
private LocalDate todoDate; // To do 날짜
}
수정 DTO 추가
// Todo 수정
@Transactional
public void updateStudyTodo(StudyTodoUpdateRequest request, Long todoId) {
// To do 조회
StudyTodo studyTodo = studyTodoRepository.findById(todoId).orElseThrow(() -> {
log.warn(">>>> {} : {} <<<<", todoId, ExceptionMessage.TODO_NOT_FOUND.getText());
return new TodoException(ExceptionMessage.TODO_NOT_FOUND);
});
// 기존 To do 업데이트
studyTodo.updateStudyTodo(
request.getTitle(),
request.getDetail(),
request.getTodoLink(),
request.getTodoDate());
}
기존 Todo 업데이트 Service 구현
테스트
// 테스트용 To do 수정
public static StudyTodoUpdateRequest updateStudyTodoRequest(String title, String detail, String todoLink, LocalDate todoDate) {
return StudyTodoUpdateRequest.builder()
.title(title)
.detail(detail)
.todoLink(todoLink)
.todoDate(todoDate)
.build();
}
테스트용 Todo Fixture 설정
@Test
public void Todo_수정_테스트() throws Exception {
//given
User savedUser = userRepository.save(generateAuthUser());
Map<String, String> map = TokenUtil.createTokenMap(savedUser);
String accessToken = jwtService.generateAccessToken(map, savedUser);
String refreshToken = jwtService.generateRefreshToken(map, savedUser);
StudyInfo studyInfo = StudyInfoFixture.createDefaultPublicStudyInfo(savedUser.getId());
studyInfoRepository.save(studyInfo);
StudyTodo studyTodo = StudyTodoFixture.createStudyTodo(studyInfo.getId());
studyTodoRepository.save(studyTodo);
StudyTodoUpdateRequest updateRequest = StudyTodoUpdateRequest.builder()
.title(studyTodo.getTitle())
.detail(studyTodo.getDetail())
.todoLink(studyTodo.getTodoLink())
.todoDate(studyTodo.getTodoDate())
.build();
//when
doNothing().when(studyMemberService).isValidateStudyLeader(any(User.class), any(Long.class));
doNothing().when(studyTodoService).updateStudyTodo(any(StudyTodoUpdateRequest.class), any(Long.class));
//then
mockMvc.perform(put("/study/" + studyInfo.getId() + "/todo/" + studyTodo.getId())
.contentType(MediaType.APPLICATION_JSON)
.header(AUTHORIZATION, createAuthorizationHeader(accessToken, refreshToken))
.content(objectMapper.writeValueAsString(updateRequest)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.res_code").value(200))
.andExpect(jsonPath("$.res_msg").value("OK"))
.andExpect(jsonPath("$.res_obj").value("Todo update Success"))
.andDo(print());
}
컨트롤러 동작 검증 ( HTTP 요청을 올바르게 처리하고 적절한 응답을 반환하는지 확인)
@Test
@DisplayName("Todo 수정 테스트")
public void updateTodo() {
//given
User leader = userRepository.save(generateAuthUser());
StudyInfo studyInfo = StudyInfoFixture.createDefaultPublicStudyInfo(leader.getId());
studyInfoRepository.save(studyInfo);
StudyTodo studyTodo = StudyTodoFixture.createStudyTodo(studyInfo.getId());
studyTodoRepository.save(studyTodo);
String updatedTitle = "제목변경";
String updatedDetail = "설명변경";
String updatedTodoLink = "링크변경";
LocalDate updatedTodoDate = LocalDate.now().plusDays(3);
StudyTodoUpdateRequest request = StudyTodoFixture.updateStudyTodoRequest(updatedTitle, updatedDetail, updatedTodoLink, updatedTodoDate);
// when
studyTodoService.updateStudyTodo(request, studyTodo.getId());
// then
StudyTodo updatedTodo = studyTodoRepository.findById(studyTodo.getId())
.orElseThrow(() -> new TodoException(ExceptionMessage.TODO_NOT_FOUND));
assertEquals(updatedTitle, updatedTodo.getTitle());
assertEquals(updatedDetail, updatedTodo.getDetail());
assertEquals(updatedTodoLink, updatedTodo.getTodoLink());
assertEquals(updatedTodoDate, updatedTodo.getTodoDate());
}
Todo 수정 Service 테스트
'Project > 깃터디 (gitudy)' 카테고리의 다른 글
[깃터디/Todo] 스터디원의 Todo 완료여부 조회 api 구현 (0) | 2024.05.11 |
---|---|
[깃터디/Todo] Todo 삭제 api 구현 (0) | 2024.05.11 |
[깃터디/Todo] Todo 조회 api 구현 (2) | 2024.05.11 |
[깃터디/Todo] Todo 등록 api 구현 (0) | 2024.05.11 |
[깃터디/Auth] 닉네임 중복검사 api 구현 (0) | 2024.05.10 |
댓글