From 2c1510015e02f7e881306f4a0fd3ac85841b291d Mon Sep 17 00:00:00 2001 From: Moojun Date: Sat, 14 Oct 2023 16:43:13 +0900 Subject: [PATCH] #14 - feat: Comment API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * CommentServiceTest * delete() 요청 시 CommentController 응답 양식 수정 * swagger 문서 일부 수정 * update 메서드 Put -> Patch로 수정 --- .../community/controller/BoardController.java | 2 +- .../controller/CommentController.java | 9 +- .../community/controller/PostController.java | 4 +- .../community/dto/request/CommentRequest.java | 2 +- .../dto/request/CommentUpdateRequest.java | 2 +- .../dto/response/CommentDeleteResponse.java | 15 + .../community/service/CommentService.java | 6 +- .../comment/delete/delete_OK.java | 22 +- .../comment/delete/delete_UNAUTHORIZED.java | 4 +- .../comment/save/save_BAD_REQUEST.java | 21 +- .../comment/save/save_UNAUTHORIZED.java | 2 +- .../comment/update/update_UNAUTHORIZED.java | 4 +- .../global/exception/ErrorCode.java | 2 +- .../community/service/CommentServiceTest.java | 272 ++++++++++++++++++ 14 files changed, 328 insertions(+), 39 deletions(-) create mode 100644 src/main/java/org/ai/roboadvisor/domain/community/dto/response/CommentDeleteResponse.java create mode 100644 src/test/java/org/ai/roboadvisor/domain/community/service/CommentServiceTest.java diff --git a/src/main/java/org/ai/roboadvisor/domain/community/controller/BoardController.java b/src/main/java/org/ai/roboadvisor/domain/community/controller/BoardController.java index d0e0906..63d0176 100644 --- a/src/main/java/org/ai/roboadvisor/domain/community/controller/BoardController.java +++ b/src/main/java/org/ai/roboadvisor/domain/community/controller/BoardController.java @@ -25,7 +25,7 @@ @Slf4j @RequiredArgsConstructor -@Tag(name = "community] board", description = "게시글 전체 불러오기 API") +@Tag(name = "community] board API", description = "게시글 목록 불러오기 API") @RestController @RequestMapping("/api/community/board") public class BoardController { diff --git a/src/main/java/org/ai/roboadvisor/domain/community/controller/CommentController.java b/src/main/java/org/ai/roboadvisor/domain/community/controller/CommentController.java index d859e89..547689a 100644 --- a/src/main/java/org/ai/roboadvisor/domain/community/controller/CommentController.java +++ b/src/main/java/org/ai/roboadvisor/domain/community/controller/CommentController.java @@ -7,6 +7,7 @@ import org.ai.roboadvisor.domain.community.dto.request.CommentDeleteRequest; import org.ai.roboadvisor.domain.community.dto.request.CommentRequest; import org.ai.roboadvisor.domain.community.dto.request.CommentUpdateRequest; +import org.ai.roboadvisor.domain.community.dto.response.CommentDeleteResponse; import org.ai.roboadvisor.domain.community.dto.response.CommentResponse; import org.ai.roboadvisor.domain.community.service.CommentService; import org.ai.roboadvisor.domain.community.swagger_annotation.comment.delete.*; @@ -21,7 +22,7 @@ @Slf4j @RequiredArgsConstructor -@Tag(name = "community] comment", description = "댓글 작성, 수정, 삭제 API") +@Tag(name = "community] comment API", description = "댓글 작성, 수정, 삭제 API") @RestController @RequestMapping("/api/community/comment") public class CommentController { @@ -46,7 +47,7 @@ public ResponseEntity> save(@PathVariable("p @update_BAD_REQUEST @update_UNAUTHORIZED @ApiResponse_Internal_Server_Error - @PutMapping("/{postId}") + @PatchMapping("/{postId}") public ResponseEntity> update(@PathVariable("postId") Long postId, @RequestBody CommentUpdateRequest commentUpdateRequest) { return ResponseEntity.status(HttpStatus.OK) @@ -60,8 +61,8 @@ public ResponseEntity> update(@PathVariable( @delete_UNAUTHORIZED @ApiResponse_Internal_Server_Error @DeleteMapping("/{postId}") - public ResponseEntity> delete(@PathVariable("postId") Long postId, - @RequestBody CommentDeleteRequest commentDeleteRequest) { + public ResponseEntity> delete(@PathVariable("postId") Long postId, + @RequestBody CommentDeleteRequest commentDeleteRequest) { return ResponseEntity.status(HttpStatus.OK) .body(SuccessApiResponse.success(SuccessCode.COMMENT_DELETE_SUCCESS, commentService.delete(postId, commentDeleteRequest))); diff --git a/src/main/java/org/ai/roboadvisor/domain/community/controller/PostController.java b/src/main/java/org/ai/roboadvisor/domain/community/controller/PostController.java index b354cc6..16fcddc 100644 --- a/src/main/java/org/ai/roboadvisor/domain/community/controller/PostController.java +++ b/src/main/java/org/ai/roboadvisor/domain/community/controller/PostController.java @@ -27,7 +27,7 @@ @Slf4j @RequiredArgsConstructor -@Tag(name = "community] post", description = "게시글 CRUD API") +@Tag(name = "community] post API", description = "게시글 CRUD API") @RestController @RequestMapping("/api/community/post") public class PostController { @@ -60,7 +60,7 @@ public ResponseEntity> save(@RequestBody PostRe @update_BAD_REQUEST @update_UNAUTHORIZED @ApiResponse_Internal_Server_Error - @PutMapping("/{postId}") + @PatchMapping("/{postId}") public ResponseEntity> update(@PathVariable("postId") Long postId, @RequestBody PostRequest postRequest) { return ResponseEntity.status(HttpStatus.OK) .body(SuccessApiResponse.success(SuccessCode.POST_UPDATE_SUCCESS, diff --git a/src/main/java/org/ai/roboadvisor/domain/community/dto/request/CommentRequest.java b/src/main/java/org/ai/roboadvisor/domain/community/dto/request/CommentRequest.java index 57b4705..932fb10 100644 --- a/src/main/java/org/ai/roboadvisor/domain/community/dto/request/CommentRequest.java +++ b/src/main/java/org/ai/roboadvisor/domain/community/dto/request/CommentRequest.java @@ -23,7 +23,7 @@ public class CommentRequest { @NotBlank private String nickname; - @Schema(description = "댓글 내용", example = "안녕하세요. 댓글 작성 1입니다. ") + @Schema(description = "댓글 내용", example = "안녕하세요. 댓글 작성 1입니다.") @NotBlank private String content; diff --git a/src/main/java/org/ai/roboadvisor/domain/community/dto/request/CommentUpdateRequest.java b/src/main/java/org/ai/roboadvisor/domain/community/dto/request/CommentUpdateRequest.java index 925ff6e..edb257f 100644 --- a/src/main/java/org/ai/roboadvisor/domain/community/dto/request/CommentUpdateRequest.java +++ b/src/main/java/org/ai/roboadvisor/domain/community/dto/request/CommentUpdateRequest.java @@ -12,7 +12,7 @@ @AllArgsConstructor public class CommentUpdateRequest { - @Schema(description = "댓글 번호", example = "1") + @Schema(description = "댓글 고유 번호", example = "1") private Long commentId; @Schema(description = "사용자의 닉네임", example = "testUser") diff --git a/src/main/java/org/ai/roboadvisor/domain/community/dto/response/CommentDeleteResponse.java b/src/main/java/org/ai/roboadvisor/domain/community/dto/response/CommentDeleteResponse.java new file mode 100644 index 0000000..0f0adaf --- /dev/null +++ b/src/main/java/org/ai/roboadvisor/domain/community/dto/response/CommentDeleteResponse.java @@ -0,0 +1,15 @@ +package org.ai.roboadvisor.domain.community.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.ai.roboadvisor.domain.community.entity.Comment; + +@Getter +@AllArgsConstructor +public class CommentDeleteResponse { + private Long id; + + public static CommentDeleteResponse fromCommentEntity(Comment comment) { + return new CommentDeleteResponse(comment.getId()); + } +} diff --git a/src/main/java/org/ai/roboadvisor/domain/community/service/CommentService.java b/src/main/java/org/ai/roboadvisor/domain/community/service/CommentService.java index c2c6c0e..b400d19 100644 --- a/src/main/java/org/ai/roboadvisor/domain/community/service/CommentService.java +++ b/src/main/java/org/ai/roboadvisor/domain/community/service/CommentService.java @@ -5,6 +5,7 @@ import org.ai.roboadvisor.domain.community.dto.request.CommentDeleteRequest; import org.ai.roboadvisor.domain.community.dto.request.CommentRequest; import org.ai.roboadvisor.domain.community.dto.request.CommentUpdateRequest; +import org.ai.roboadvisor.domain.community.dto.response.CommentDeleteResponse; import org.ai.roboadvisor.domain.community.dto.response.CommentResponse; import org.ai.roboadvisor.domain.community.entity.Comment; import org.ai.roboadvisor.domain.community.entity.DeleteStatus; @@ -30,6 +31,7 @@ public CommentResponse save(Long postId, CommentRequest commentRequest) { Tendency commentTendency = commentRequest.getTendency(); checkTendencyIsValid(commentTendency); + // 게시글의 tendency와 댓글의 tendency가 일치하는지 검증 Post existPost = postRepository.findPostById(postId) .orElseThrow(() -> new CustomException(ErrorCode.POST_ID_NOT_EXISTS)); checkCommentIsValid(commentTendency, existPost); @@ -55,7 +57,7 @@ public CommentResponse update(Long postId, CommentUpdateRequest commentUpdateReq } @Transactional - public CommentResponse delete(Long postId, CommentDeleteRequest commentDeleteRequest) { + public CommentDeleteResponse delete(Long postId, CommentDeleteRequest commentDeleteRequest) { Comment existingComment = findExistingCommentById(postId, commentDeleteRequest.getCommentId()); // validate if user has authority @@ -64,7 +66,7 @@ public CommentResponse delete(Long postId, CommentDeleteRequest commentDeleteReq // manually delete a comment deleteComment(existingComment); - return CommentResponse.fromCommentEntity(existingComment); + return CommentDeleteResponse.fromCommentEntity(existingComment); } private void checkTendencyIsValid(Tendency tendency) { diff --git a/src/main/java/org/ai/roboadvisor/domain/community/swagger_annotation/comment/delete/delete_OK.java b/src/main/java/org/ai/roboadvisor/domain/community/swagger_annotation/comment/delete/delete_OK.java index 3501ce9..50dea6f 100644 --- a/src/main/java/org/ai/roboadvisor/domain/community/swagger_annotation/comment/delete/delete_OK.java +++ b/src/main/java/org/ai/roboadvisor/domain/community/swagger_annotation/comment/delete/delete_OK.java @@ -12,23 +12,21 @@ @Retention(RetentionPolicy.RUNTIME) @Inherited @ApiResponse(responseCode = "200", description = """ - 댓글이 정상적으로 삭제된 경우: data 내에 응답 객체는 '댓글 작성', '댓글 수정' 과 동일하다. + 댓글이 정상적으로 삭제된 경우: + + "data" 값으로 삭제 요청된 댓글의 id값을 리턴한다. """, content = @Content(schema = @Schema(implementation = SuccessApiResponse.class), examples = @ExampleObject(name = "example", description = "정상 응답 예시", value = """ - { - "code": 200, - "message": "댓글 삭제가 정상적으로 처리되었습니다", - "data": { - "id": 1, - "postId": 1, - "nickname": "testUser", - "content": "안녕하세요 댓글 1", - "createdDateTime": "2023-09-25 04:28:41" - } - } + { + "code": 200, + "message": "댓글 삭제가 정상적으로 처리되었습니다", + "data": { + "id": 3 + } + } """ ))) public @interface delete_OK { diff --git a/src/main/java/org/ai/roboadvisor/domain/community/swagger_annotation/comment/delete/delete_UNAUTHORIZED.java b/src/main/java/org/ai/roboadvisor/domain/community/swagger_annotation/comment/delete/delete_UNAUTHORIZED.java index 6effdce..55eac29 100644 --- a/src/main/java/org/ai/roboadvisor/domain/community/swagger_annotation/comment/delete/delete_UNAUTHORIZED.java +++ b/src/main/java/org/ai/roboadvisor/domain/community/swagger_annotation/comment/delete/delete_UNAUTHORIZED.java @@ -11,10 +11,10 @@ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Inherited -@ApiResponse(responseCode = "401", description = "게시글과 댓글의 투자 성향이 다른 경우, 즉 댓글 작성 권한이 없는 경우", +@ApiResponse(responseCode = "401", description = "댓글 삭제 권한이 없는 경우", content = @Content(schema = @Schema(implementation = SuccessApiResponse.class), examples = @ExampleObject(name = "example", - description = "게시글과 댓글의 투자 성향이 다른 경우 예시", + description = "댓글 삭제 권한이 없는 경우 예시", value = """ { "code": 401, diff --git a/src/main/java/org/ai/roboadvisor/domain/community/swagger_annotation/comment/save/save_BAD_REQUEST.java b/src/main/java/org/ai/roboadvisor/domain/community/swagger_annotation/comment/save/save_BAD_REQUEST.java index 605edd5..804d7af 100644 --- a/src/main/java/org/ai/roboadvisor/domain/community/swagger_annotation/comment/save/save_BAD_REQUEST.java +++ b/src/main/java/org/ai/roboadvisor/domain/community/swagger_annotation/comment/save/save_BAD_REQUEST.java @@ -11,21 +11,22 @@ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Inherited -@ApiResponse(responseCode = "400", description = "게시글 번호가 잘못 입력된 경우, 혹은 존재하지 않는 경우", +@ApiResponse(responseCode = "400", description = """ + 투자 성향이 LION(공격투자형), SNAKE(적극투자형), MONKEY(위험중립형), SHEEP(안정추구형) 외에 다른 값이 들어온 경우, + + 즉, 존재하지 않는 투자 성향이 입력된 경우 + """, content = @Content(schema = @Schema(implementation = SuccessApiResponse.class), - examples = - @ExampleObject(name = "example", - description = "게시글 번호가 잘못 입력된 경우, 혹은 존재하지 않는 경우 예시", + examples = @ExampleObject(name = "example", + description = "투자 성향이 잘못 입력된 경우 예시", value = """ { - "code": 400, - "message": "요청하신 게시글 id가 존재하지 않습니다.", - "data": null + "code": 400, + "message": "잘못된 투자 성향 형식이 입력되었습니다", + "data": null } """ - ) - - )) + ))) public @interface save_BAD_REQUEST { } diff --git a/src/main/java/org/ai/roboadvisor/domain/community/swagger_annotation/comment/save/save_UNAUTHORIZED.java b/src/main/java/org/ai/roboadvisor/domain/community/swagger_annotation/comment/save/save_UNAUTHORIZED.java index 085739f..5a44a62 100644 --- a/src/main/java/org/ai/roboadvisor/domain/community/swagger_annotation/comment/save/save_UNAUTHORIZED.java +++ b/src/main/java/org/ai/roboadvisor/domain/community/swagger_annotation/comment/save/save_UNAUTHORIZED.java @@ -18,7 +18,7 @@ value = """ { "code": 401, - "message": "게시글 수정 혹은 삭제 권한이 존재하지 않습니다", + "message": "게시글과 댓글의 투자 성향이 달라서 댓글을 작성할 수 없습니다", "data": null } """ diff --git a/src/main/java/org/ai/roboadvisor/domain/community/swagger_annotation/comment/update/update_UNAUTHORIZED.java b/src/main/java/org/ai/roboadvisor/domain/community/swagger_annotation/comment/update/update_UNAUTHORIZED.java index de31eee..5475f0f 100644 --- a/src/main/java/org/ai/roboadvisor/domain/community/swagger_annotation/comment/update/update_UNAUTHORIZED.java +++ b/src/main/java/org/ai/roboadvisor/domain/community/swagger_annotation/comment/update/update_UNAUTHORIZED.java @@ -11,10 +11,10 @@ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Inherited -@ApiResponse(responseCode = "401", description = "게시글과 댓글의 투자 성향이 다른 경우, 즉 댓글 작성 권한이 없는 경우", +@ApiResponse(responseCode = "401", description = "댓글 수정 권한이 없는 경우, 즉 작성자와 수정을 요청한 사용자의 닉네임이 다른 경우", content = @Content(schema = @Schema(implementation = SuccessApiResponse.class), examples = @ExampleObject(name = "example", - description = "게시글과 댓글의 투자 성향이 다른 경우 예시", + description = "댓글 수정 권한이 없는 경우", value = """ { "code": 401, diff --git a/src/main/java/org/ai/roboadvisor/global/exception/ErrorCode.java b/src/main/java/org/ai/roboadvisor/global/exception/ErrorCode.java index 0cae561..9f91d40 100644 --- a/src/main/java/org/ai/roboadvisor/global/exception/ErrorCode.java +++ b/src/main/java/org/ai/roboadvisor/global/exception/ErrorCode.java @@ -24,7 +24,7 @@ public enum ErrorCode { POST_ID_NOT_EXISTS(HttpStatus.BAD_REQUEST, "C001", "요청하신 게시글 id가 존재하지 않습니다."), USER_HAS_NOT_AUTHORIZED(HttpStatus.UNAUTHORIZED, "CO02", "사용자에게 권한이 존재하지 않습니다"), TENDENCY_NOT_MATCH_BETWEEN_POST_AND_COMMENT(HttpStatus.UNAUTHORIZED, - "CO03", "게시글 수정 혹은 삭제 권한이 존재하지 않습니다"), + "CO03", "게시글과 댓글의 투자 성향이 달라서 댓글을 작성할 수 없습니다"), // tendency TENDENCY_INPUT_INVALID(HttpStatus.BAD_REQUEST, "TE01", "잘못된 투자 성향 형식이 입력되었습니다"); diff --git a/src/test/java/org/ai/roboadvisor/domain/community/service/CommentServiceTest.java b/src/test/java/org/ai/roboadvisor/domain/community/service/CommentServiceTest.java new file mode 100644 index 0000000..08d3e8b --- /dev/null +++ b/src/test/java/org/ai/roboadvisor/domain/community/service/CommentServiceTest.java @@ -0,0 +1,272 @@ +package org.ai.roboadvisor.domain.community.service; + +import org.ai.roboadvisor.domain.community.dto.request.CommentDeleteRequest; +import org.ai.roboadvisor.domain.community.dto.request.CommentRequest; +import org.ai.roboadvisor.domain.community.dto.request.CommentUpdateRequest; +import org.ai.roboadvisor.domain.community.dto.response.CommentDeleteResponse; +import org.ai.roboadvisor.domain.community.dto.response.CommentResponse; +import org.ai.roboadvisor.domain.community.entity.Comment; +import org.ai.roboadvisor.domain.community.entity.DeleteStatus; +import org.ai.roboadvisor.domain.community.entity.Post; +import org.ai.roboadvisor.domain.community.repository.CommentRepository; +import org.ai.roboadvisor.domain.community.repository.PostRepository; +import org.ai.roboadvisor.domain.tendency.entity.Tendency; +import org.ai.roboadvisor.global.exception.CustomException; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Optional; + +import static org.assertj.core.api.Assertions.*; + + +@Transactional +@SpringBootTest +@ActiveProfiles("test") +@Sql(scripts = {"classpath:schema-truncate.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) +class CommentServiceTest { + + @Autowired + private CommentService commentService; + + @Autowired + private PostRepository postRepository; + + @Autowired + private CommentRepository commentRepository; + + private final Long POST_ID = 1L; + private final String POST_NICKNAME = "post_user"; + private final Tendency POST_TENDENCY = Tendency.LION; + private final String POST_CONTENT = "post_content"; + + private final Long COMMENT_ID = 1L; + private final String COMMENT_NICKNAME = "comment_user"; + private final Tendency COMMENT_TENDENCY = Tendency.LION; + private final String COMMENT_CONTENT = "comment_content"; + + @BeforeEach + void setUp() { + // 게시글 하나를 미리 저장 + Post post = Post.builder() + .nickname(POST_NICKNAME) + .tendency(POST_TENDENCY) + .content(POST_CONTENT) + .viewCount(0L) + .deleteStatus(DeleteStatus.F) + .build(); + postRepository.save(post); + + // 댓글 하나도 미리 저장 + Comment comment = Comment.builder() + .nickname(COMMENT_NICKNAME) + .content(COMMENT_CONTENT) + .deleteStatus(DeleteStatus.F) + .post(post) + .build(); + post.getComments().add(comment); + commentRepository.save(comment); + } + + @Test + @DisplayName("case 1: Tendency(투자 성향)이 적절하지 않은 타입이 온 경우, 예외처리") + void save_with_TendencyIsNotValid() { + Tendency notExists = Tendency.TYPE_NOT_EXISTS; + CommentRequest request = new CommentRequest( + notExists, "test_nickname", "test_content"); + + Assertions.assertThrows(CustomException.class, () -> + commentService.save(POST_ID, request)); + } + + @Test + @DisplayName("case 2: 게시글과 댓글의 Tendency(투자 성향)이 일치하지 않는 경우, 예외처리") + void save_with_Tendency_is_not_same_between_post_and_comment() { + Tendency different = Tendency.SHEEP; // @BeforeEach에서 저장된 post는 LION + CommentRequest request = new CommentRequest( + different, "test_nickname", "test_content"); + + Assertions.assertThrows(CustomException.class, () -> + commentService.save(POST_ID, request)); + } + + @Test + @DisplayName("case 3: 정상 로직") + void save() { + // given + Tendency tendency = POST_TENDENCY; + String nickname = "새로운 댓글 작성자"; + String content = "댓글 작성 테스트"; + CommentRequest request = new CommentRequest(tendency, nickname, content); + + // when + CommentResponse response = commentService.save(POST_ID, request); + + // then + assertThat(response.getNickname()).isEqualTo(nickname); + assertThat(response.getPostId()).isEqualTo(POST_ID); + assertThat(response.getContent()).isEqualTo(content); + } + + @Test + @DisplayName("case 1: 게시글 id가 존재하지 않는 경우, 예외처리") + void update_when_post_id_not_exists() { + String updateContent = "Update the content"; + CommentUpdateRequest request = new CommentUpdateRequest(COMMENT_ID, COMMENT_NICKNAME, + updateContent); + Long postIdNotExists = 1000L; + + Assertions.assertThrows(CustomException.class, () -> + commentService.update(postIdNotExists, request)); + } + + @Test + @DisplayName("case 2: 게시글 id가 존재하지만, 댓글 id와 게시글 정보로 댓글 Entity를 찾지 못했을 때, 오류처리") + void update_when_comment_is_not_in_db() { + String updateContent = "Update the content"; + + // 1: 댓글 id가 db에 없는 경우 + Long commentIdNotExists = 1000L; + CommentUpdateRequest request = new CommentUpdateRequest(commentIdNotExists, COMMENT_NICKNAME, + updateContent); + Assertions.assertThrows(CustomException.class, () -> + commentService.update(POST_ID, request)); + + // 2: 댓글 id가 db에 존재하지만, 연관관계가 없는 게시글과 댓글을 조회하는 경우 + // 게시글, 댓글 하나씩 더 저장 + Post post = Post.builder() + .nickname(POST_NICKNAME) + .tendency(POST_TENDENCY) + .content(POST_CONTENT) + .viewCount(0L) + .deleteStatus(DeleteStatus.F) + .build(); + postRepository.save(post); + Comment comment = Comment.builder() + .nickname(COMMENT_NICKNAME) + .content(COMMENT_CONTENT) + .deleteStatus(DeleteStatus.F) + .post(post) + .build(); + post.getComments().add(comment); + commentRepository.save(comment); + + Long commentId = 2L; // 이 부분이 변경됨. + CommentUpdateRequest request2 = new CommentUpdateRequest(commentId, COMMENT_NICKNAME, + updateContent); + Assertions.assertThrows(CustomException.class, () -> + commentService.update(POST_ID, request2)); + } + + @Test + @DisplayName("case 3: 댓글 수정 권한이 없는 경우, 예외처리") + void update_authorization_is_not_valid() { + String nickname = "not_authorized"; + CommentUpdateRequest request = new CommentUpdateRequest(COMMENT_ID, nickname, + COMMENT_CONTENT); + + Assertions.assertThrows(CustomException.class, () -> + commentService.update(POST_ID, request)); + } + + @Test + @DisplayName("case 4: 정상 수정 로직") + void update() { + // given + String updateContent = "Update the content"; + CommentUpdateRequest request = new CommentUpdateRequest(COMMENT_ID, COMMENT_NICKNAME, + updateContent); + + // when + CommentResponse response = commentService.update(POST_ID, request); + + // then + assertThat(response.getId()).isEqualTo(COMMENT_ID); + assertThat(response.getPostId()).isEqualTo(POST_ID); + assertThat(response.getNickname()).isEqualTo(COMMENT_NICKNAME); + assertThat(response.getContent()).isEqualTo(updateContent); // here is updated + } + + @Test + @DisplayName("case 1: 게시글 id가 존재하지 않는 경우, 예외처리") + void delete_when_post_id_not_exists() { + CommentDeleteRequest request = new CommentDeleteRequest(COMMENT_ID, COMMENT_NICKNAME); + Long postIdNotExists = 1000L; + + Assertions.assertThrows(CustomException.class, () -> + commentService.delete(postIdNotExists, request)); + } + + @Test + @DisplayName("case 2: 게시글 id가 존재하지만, 댓글 id와 게시글 정보로 댓글 Entity를 찾지 못했을 때, 오류처리") + void delete_when_comment_is_not_in_db() { + // 1: 댓글 id가 db에 없는 경우 + Long commentIdNotExists = 1000L; + CommentDeleteRequest request = new CommentDeleteRequest(commentIdNotExists, COMMENT_NICKNAME); + Assertions.assertThrows(CustomException.class, () -> + commentService.delete(POST_ID, request)); + + // 2: 댓글 id가 db에 존재하지만, 연관관계가 없는 게시글과 댓글을 조회하는 경우 + // 게시글, 댓글 하나씩 더 저장 + Post post = Post.builder() + .nickname(POST_NICKNAME) + .tendency(POST_TENDENCY) + .content(POST_CONTENT) + .viewCount(0L) + .deleteStatus(DeleteStatus.F) + .build(); + postRepository.save(post); + Comment comment = Comment.builder() + .nickname(COMMENT_NICKNAME) + .content(COMMENT_CONTENT) + .deleteStatus(DeleteStatus.F) + .post(post) + .build(); + post.getComments().add(comment); + commentRepository.save(comment); + + Long commentId = 2L; // 이 부분이 변경됨. + CommentDeleteRequest request2 = new CommentDeleteRequest(commentId, COMMENT_NICKNAME); + Assertions.assertThrows(CustomException.class, () -> + commentService.delete(POST_ID, request2)); + } + + @Test + @DisplayName("case 3: 댓글 삭제 권한이 없는 경우, 예외처리") + void delete_authorization_is_not_valid() { + String nickname = "not_authorized"; + CommentDeleteRequest request = new CommentDeleteRequest(COMMENT_ID, nickname); + + Assertions.assertThrows(CustomException.class, () -> + commentService.delete(POST_ID, request)); + } + + @Test + @DisplayName("case 4: 정상 삭제 로직") + void delete() { + // given + CommentDeleteRequest request = new CommentDeleteRequest(COMMENT_ID, COMMENT_NICKNAME); + + // when + CommentDeleteResponse response = commentService.delete(POST_ID, request); + + // then + assertThat(response.getId()).isEqualTo(COMMENT_ID); + + // DeleteStatus = 'T' 로 변경되었는지 검증 + Optional existingPostOptional = postRepository.findPostById(POST_ID); + Optional existingCommentOptional = commentRepository.findCommentByIdAndPost(COMMENT_ID, existingPostOptional.get()); + Comment existingComment = existingCommentOptional.get(); + + assertThat(existingComment.getId()).isEqualTo(COMMENT_ID); + assertThat(existingComment.getPost().getId()).isEqualTo(POST_ID); + assertThat(existingComment.getDeleteStatus()).isEqualTo(DeleteStatus.T); + } +} \ No newline at end of file