From 5d2755c76042c07b4ecc9b36e8f30b2f831a5030 Mon Sep 17 00:00:00 2001 From: woo-chang Date: Wed, 26 Jul 2023 16:51:55 +0900 Subject: [PATCH 01/14] =?UTF-8?q?feat:=20(#128)=20=EB=8C=93=EA=B8=80=20?= =?UTF-8?q?=EB=8F=84=EB=A9=94=EC=9D=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../votogether/domain/post/entity/Post.java | 12 +++++ .../domain/post/entity/comment/Comment.java | 48 +++++++++++++++++++ .../domain/post/entity/comment/Content.java | 35 ++++++++++++++ .../post/entity/comment/CommentTest.java | 42 ++++++++++++++++ 4 files changed, 137 insertions(+) create mode 100644 backend/src/main/java/com/votogether/domain/post/entity/comment/Comment.java create mode 100644 backend/src/main/java/com/votogether/domain/post/entity/comment/Content.java create mode 100644 backend/src/test/java/com/votogether/domain/post/entity/comment/CommentTest.java diff --git a/backend/src/main/java/com/votogether/domain/post/entity/Post.java b/backend/src/main/java/com/votogether/domain/post/entity/Post.java index 6248270ec..bc728fdb0 100644 --- a/backend/src/main/java/com/votogether/domain/post/entity/Post.java +++ b/backend/src/main/java/com/votogether/domain/post/entity/Post.java @@ -3,9 +3,11 @@ import com.votogether.domain.category.entity.Category; import com.votogether.domain.common.BaseEntity; import com.votogether.domain.member.entity.Member; +import com.votogether.domain.post.entity.comment.Comment; import com.votogether.domain.post.exception.PostExceptionType; import com.votogether.domain.vote.entity.Vote; import com.votogether.exception.BadRequestException; +import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Embedded; import jakarta.persistence.Entity; @@ -15,7 +17,9 @@ import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; import java.time.LocalDateTime; +import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.stream.IntStream; @@ -50,6 +54,9 @@ public class Post extends BaseEntity { @Column(columnDefinition = "datetime(2)", nullable = false) private LocalDateTime deadline; + @OneToMany(mappedBy = "post", cascade = CascadeType.PERSIST) + private List comments = new ArrayList<>(); + @Builder private Post( final Member member, @@ -129,4 +136,9 @@ private void validatePostOption(PostOption postOption) { } } + public void addComment(final Comment comment) { + comments.add(comment); + comment.setPost(this); + } + } diff --git a/backend/src/main/java/com/votogether/domain/post/entity/comment/Comment.java b/backend/src/main/java/com/votogether/domain/post/entity/comment/Comment.java new file mode 100644 index 000000000..e08724290 --- /dev/null +++ b/backend/src/main/java/com/votogether/domain/post/entity/comment/Comment.java @@ -0,0 +1,48 @@ +package com.votogether.domain.post.entity.comment; + +import com.votogether.domain.common.BaseEntity; +import com.votogether.domain.member.entity.Member; +import com.votogether.domain.post.entity.Post; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Getter +@Entity +public class Comment extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Setter + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "post_id", nullable = false) + private Post post; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id", nullable = false) + private Member member; + + @Embedded + private Content content; + + @Builder + private Comment(final Post post, final Member member, final String content) { + this.post = post; + this.member = member; + this.content = new Content(content); + } + +} diff --git a/backend/src/main/java/com/votogether/domain/post/entity/comment/Content.java b/backend/src/main/java/com/votogether/domain/post/entity/comment/Content.java new file mode 100644 index 000000000..292ae1184 --- /dev/null +++ b/backend/src/main/java/com/votogether/domain/post/entity/comment/Content.java @@ -0,0 +1,35 @@ +package com.votogether.domain.post.entity.comment; + +import com.votogether.domain.post.exception.CommentExceptionType; +import com.votogether.exception.BadRequestException; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Getter +@Embeddable +class Content { + + private static final int MAXIMUM_LENGTH = 500; + + @Column(name = "content", nullable = false, length = MAXIMUM_LENGTH) + private String value; + + public Content(final String value) { + validate(value); + this.value = value; + } + + private void validate(final String content) { + if (content.length() > MAXIMUM_LENGTH) { + throw new BadRequestException( + CommentExceptionType.INVALID_CONTENT_LENGTH.getCode(), + String.format("댓글 길이는 최대 %d자까지 가능합니다.", MAXIMUM_LENGTH) + ); + } + } + +} diff --git a/backend/src/test/java/com/votogether/domain/post/entity/comment/CommentTest.java b/backend/src/test/java/com/votogether/domain/post/entity/comment/CommentTest.java new file mode 100644 index 000000000..a3af46bf5 --- /dev/null +++ b/backend/src/test/java/com/votogether/domain/post/entity/comment/CommentTest.java @@ -0,0 +1,42 @@ +package com.votogether.domain.post.entity.comment; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.votogether.domain.post.entity.Post; +import com.votogether.domain.post.entity.PostBody; +import com.votogether.exception.BadRequestException; +import com.votogether.fixtures.MemberFixtures; +import java.time.LocalDateTime; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class CommentTest { + + @Test + @DisplayName("댓글 내용이 최대 글자를 초과하면 예외를 던진다.") + void invalidContentLength() { + // given + String content = "a".repeat(501); + PostBody body = PostBody.builder() + .title("title") + .content("content") + .build(); + Post post = Post.builder() + .member(MemberFixtures.FEMALE_20.get()) + .postBody(body) + .deadline(LocalDateTime.now()) + .build(); + + // when, then + assertThatThrownBy( + () -> Comment.builder() + .member(MemberFixtures.MALE_20.get()) + .post(post) + .content(content) + .build() + ) + .isInstanceOf(BadRequestException.class) + .hasMessage("댓글 길이는 최대 500자까지 가능합니다."); + } + +} From ab3cfb15caaf596898e29044a5e5f4a4071c0f77 Mon Sep 17 00:00:00 2001 From: woo-chang Date: Wed, 26 Jul 2023 16:52:30 +0900 Subject: [PATCH 02/14] =?UTF-8?q?feat:=20(#128)=20=EB=8C=93=EA=B8=80=20?= =?UTF-8?q?=EB=93=B1=EB=A1=9D=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/request/CommentRegisterRequest.java | 6 ++ .../post/exception/CommentExceptionType.java | 19 ++++++ .../post/repository/CommentRepository.java | 7 +++ .../post/service/PostCommentService.java | 35 +++++++++++ .../exception/BadRequestException.java | 4 ++ .../votogether/exception/BaseException.java | 9 ++- .../exception/ExceptionResponse.java | 3 +- .../post/service/PostCommentServiceTest.java | 59 +++++++++++++++++++ 8 files changed, 138 insertions(+), 4 deletions(-) create mode 100644 backend/src/main/java/com/votogether/domain/post/dto/request/CommentRegisterRequest.java create mode 100644 backend/src/main/java/com/votogether/domain/post/exception/CommentExceptionType.java create mode 100644 backend/src/main/java/com/votogether/domain/post/repository/CommentRepository.java create mode 100644 backend/src/main/java/com/votogether/domain/post/service/PostCommentService.java create mode 100644 backend/src/test/java/com/votogether/domain/post/service/PostCommentServiceTest.java diff --git a/backend/src/main/java/com/votogether/domain/post/dto/request/CommentRegisterRequest.java b/backend/src/main/java/com/votogether/domain/post/dto/request/CommentRegisterRequest.java new file mode 100644 index 000000000..9123ad76e --- /dev/null +++ b/backend/src/main/java/com/votogether/domain/post/dto/request/CommentRegisterRequest.java @@ -0,0 +1,6 @@ +package com.votogether.domain.post.dto.request; + +import jakarta.validation.constraints.NotBlank; + +public record CommentRegisterRequest(@NotBlank(message = "댓글 내용은 존재해야 합니다.") String content) { +} diff --git a/backend/src/main/java/com/votogether/domain/post/exception/CommentExceptionType.java b/backend/src/main/java/com/votogether/domain/post/exception/CommentExceptionType.java new file mode 100644 index 000000000..eadbe1df0 --- /dev/null +++ b/backend/src/main/java/com/votogether/domain/post/exception/CommentExceptionType.java @@ -0,0 +1,19 @@ +package com.votogether.domain.post.exception; + +import com.votogether.exception.ExceptionType; +import lombok.Getter; + +@Getter +public enum CommentExceptionType implements ExceptionType { + + INVALID_CONTENT_LENGTH(2000, "유효하지 않은 댓글 길이입니다."); + + private final int code; + private final String message; + + CommentExceptionType(final int code, final String message) { + this.code = code; + this.message = message; + } + +} diff --git a/backend/src/main/java/com/votogether/domain/post/repository/CommentRepository.java b/backend/src/main/java/com/votogether/domain/post/repository/CommentRepository.java new file mode 100644 index 000000000..28b072812 --- /dev/null +++ b/backend/src/main/java/com/votogether/domain/post/repository/CommentRepository.java @@ -0,0 +1,7 @@ +package com.votogether.domain.post.repository; + +import com.votogether.domain.post.entity.comment.Comment; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface CommentRepository extends JpaRepository { +} diff --git a/backend/src/main/java/com/votogether/domain/post/service/PostCommentService.java b/backend/src/main/java/com/votogether/domain/post/service/PostCommentService.java new file mode 100644 index 000000000..baf30e486 --- /dev/null +++ b/backend/src/main/java/com/votogether/domain/post/service/PostCommentService.java @@ -0,0 +1,35 @@ +package com.votogether.domain.post.service; + +import com.votogether.domain.member.entity.Member; +import com.votogether.domain.post.dto.request.CommentRegisterRequest; +import com.votogether.domain.post.entity.Post; +import com.votogether.domain.post.entity.comment.Comment; +import com.votogether.domain.post.exception.PostExceptionType; +import com.votogether.domain.post.repository.PostRepository; +import com.votogether.exception.BadRequestException; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@RequiredArgsConstructor +@Service +public class PostCommentService { + + private final PostRepository postRepository; + + public void registerComment( + final Member member, + final Long postId, + final CommentRegisterRequest commentRegisterRequest + ) { + final Post post = postRepository.findById(postId) + .orElseThrow(() -> new BadRequestException(PostExceptionType.POST_NOT_FOUND)); + + post.addComment( + Comment.builder() + .member(member) + .content(commentRegisterRequest.content()) + .build() + ); + } + +} diff --git a/backend/src/main/java/com/votogether/exception/BadRequestException.java b/backend/src/main/java/com/votogether/exception/BadRequestException.java index f58142bcc..2efa36d37 100644 --- a/backend/src/main/java/com/votogether/exception/BadRequestException.java +++ b/backend/src/main/java/com/votogether/exception/BadRequestException.java @@ -6,4 +6,8 @@ public BadRequestException(final ExceptionType exceptionType) { super(exceptionType); } + public BadRequestException(final int code, final String message) { + super(code, message); + } + } diff --git a/backend/src/main/java/com/votogether/exception/BaseException.java b/backend/src/main/java/com/votogether/exception/BaseException.java index 0c9754569..de12dc800 100644 --- a/backend/src/main/java/com/votogether/exception/BaseException.java +++ b/backend/src/main/java/com/votogether/exception/BaseException.java @@ -5,11 +5,16 @@ @Getter public class BaseException extends RuntimeException { - private final ExceptionType exceptionType; + private final int code; public BaseException(final ExceptionType exceptionType) { super(exceptionType.getMessage()); - this.exceptionType = exceptionType; + this.code = exceptionType.getCode(); + } + + public BaseException(final int code, final String message) { + super(message); + this.code = code; } } diff --git a/backend/src/main/java/com/votogether/exception/ExceptionResponse.java b/backend/src/main/java/com/votogether/exception/ExceptionResponse.java index 0172aa7d8..adecbcfb2 100644 --- a/backend/src/main/java/com/votogether/exception/ExceptionResponse.java +++ b/backend/src/main/java/com/votogether/exception/ExceptionResponse.java @@ -3,8 +3,7 @@ public record ExceptionResponse(int code, String message) { public static ExceptionResponse from(final BaseException e) { - final ExceptionType exceptionType = e.getExceptionType(); - return new ExceptionResponse(exceptionType.getCode(), exceptionType.getMessage()); + return new ExceptionResponse(e.getCode(), e.getMessage()); } } diff --git a/backend/src/test/java/com/votogether/domain/post/service/PostCommentServiceTest.java b/backend/src/test/java/com/votogether/domain/post/service/PostCommentServiceTest.java new file mode 100644 index 000000000..ada57c0a9 --- /dev/null +++ b/backend/src/test/java/com/votogether/domain/post/service/PostCommentServiceTest.java @@ -0,0 +1,59 @@ +package com.votogether.domain.post.service; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.votogether.ServiceTest; +import com.votogether.domain.member.entity.Member; +import com.votogether.domain.member.repository.MemberRepository; +import com.votogether.domain.post.dto.request.CommentRegisterRequest; +import com.votogether.domain.post.entity.Post; +import com.votogether.domain.post.entity.PostBody; +import com.votogether.domain.post.repository.CommentRepository; +import com.votogether.domain.post.repository.PostRepository; +import com.votogether.fixtures.MemberFixtures; +import jakarta.persistence.EntityManager; +import java.time.LocalDateTime; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +@ServiceTest +class PostCommentServiceTest { + + @Autowired + EntityManager em; + + @Autowired + PostCommentService postCommentService; + + @Autowired + MemberRepository memberRepository; + + @Autowired + PostRepository postRepository; + + @Autowired + CommentRepository commentRepository; + + @Test + @DisplayName("게시글에 댓글을 등록한다.") + void registerComment() { + // given + Member member = memberRepository.save(MemberFixtures.MALE_20.get()); + Post post = postRepository.save( + Post.builder() + .member(member) + .postBody(PostBody.builder().title("title").content("content").build()) + .deadline(LocalDateTime.of(2100, 7, 12, 0, 0)) + .build() + ); + CommentRegisterRequest commentRegisterRequest = new CommentRegisterRequest("hello"); + + // when + postCommentService.registerComment(member, post.getId(), commentRegisterRequest); + + // then + assertThat(commentRepository.findAll()).hasSize(1); + } + +} From 4b390daf9dba41a21d446e1a2e9997caddae59c9 Mon Sep 17 00:00:00 2001 From: woo-chang Date: Thu, 27 Jul 2023 00:06:44 +0900 Subject: [PATCH 03/14] =?UTF-8?q?feat:=20(#128)=20=EA=B2=8C=EC=8B=9C?= =?UTF-8?q?=EA=B8=80=20=EB=8C=93=EA=B8=80=20=EC=9E=91=EC=84=B1=20API=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/PostCommentController.java | 44 +++++++ .../dto/request/CommentRegisterRequest.java | 8 +- .../post/service/PostCommentService.java | 2 + .../exception/GlobalExceptionHandler.java | 31 +++++ .../controller/PostCommentControllerTest.java | 117 ++++++++++++++++++ 5 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 backend/src/main/java/com/votogether/domain/post/controller/PostCommentController.java create mode 100644 backend/src/test/java/com/votogether/domain/post/controller/PostCommentControllerTest.java diff --git a/backend/src/main/java/com/votogether/domain/post/controller/PostCommentController.java b/backend/src/main/java/com/votogether/domain/post/controller/PostCommentController.java new file mode 100644 index 000000000..fafaf34e5 --- /dev/null +++ b/backend/src/main/java/com/votogether/domain/post/controller/PostCommentController.java @@ -0,0 +1,44 @@ +package com.votogether.domain.post.controller; + +import com.votogether.domain.member.entity.Member; +import com.votogether.domain.post.dto.request.CommentRegisterRequest; +import com.votogether.domain.post.service.PostCommentService; +import com.votogether.global.jwt.Auth; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Tag(name = "게시글 댓글", description = "게시글 댓글 관련 API") +@RequiredArgsConstructor +@RequestMapping("/posts") +@RestController +public class PostCommentController { + + private final PostCommentService postCommentService; + + @Operation(summary = "게시글 댓글 작성", description = "게시글 댓글을 작성한다.") + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "게시글 댓글 작성 성공"), + @ApiResponse(responseCode = "404", description = "존재하지 않는 게시글에 대한 댓글 작성") + }) + @PostMapping("/{postId}/comments") + public ResponseEntity registerComment( + @Auth final Member member, + @PathVariable final Long postId, + @Valid @RequestBody CommentRegisterRequest commentRegisterRequest + ) { + postCommentService.registerComment(member, postId, commentRegisterRequest); + return ResponseEntity.status(HttpStatus.CREATED).build(); + } + +} diff --git a/backend/src/main/java/com/votogether/domain/post/dto/request/CommentRegisterRequest.java b/backend/src/main/java/com/votogether/domain/post/dto/request/CommentRegisterRequest.java index 9123ad76e..c03eab6e2 100644 --- a/backend/src/main/java/com/votogether/domain/post/dto/request/CommentRegisterRequest.java +++ b/backend/src/main/java/com/votogether/domain/post/dto/request/CommentRegisterRequest.java @@ -1,6 +1,12 @@ package com.votogether.domain.post.dto.request; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; -public record CommentRegisterRequest(@NotBlank(message = "댓글 내용은 존재해야 합니다.") String content) { +@Schema(name = "게시글 댓글 작성 요청") +public record CommentRegisterRequest( + @Schema(name = "댓글 내용", example = "hello") + @NotBlank(message = "댓글 내용은 존재해야 합니다.") + String content +) { } diff --git a/backend/src/main/java/com/votogether/domain/post/service/PostCommentService.java b/backend/src/main/java/com/votogether/domain/post/service/PostCommentService.java index baf30e486..b48a377dd 100644 --- a/backend/src/main/java/com/votogether/domain/post/service/PostCommentService.java +++ b/backend/src/main/java/com/votogether/domain/post/service/PostCommentService.java @@ -9,6 +9,7 @@ import com.votogether.exception.BadRequestException; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; @RequiredArgsConstructor @Service @@ -16,6 +17,7 @@ public class PostCommentService { private final PostRepository postRepository; + @Transactional public void registerComment( final Member member, final Long postId, diff --git a/backend/src/main/java/com/votogether/exception/GlobalExceptionHandler.java b/backend/src/main/java/com/votogether/exception/GlobalExceptionHandler.java index 01447a622..36eeb088b 100644 --- a/backend/src/main/java/com/votogether/exception/GlobalExceptionHandler.java +++ b/backend/src/main/java/com/votogether/exception/GlobalExceptionHandler.java @@ -1,10 +1,13 @@ package com.votogether.exception; +import java.util.List; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; @Slf4j @RestControllerAdvice @@ -17,6 +20,34 @@ public ResponseEntity handleException(final Exception e) { .body(new ExceptionResponse(-9999, "알 수 없는 서버 에러가 발생했습니다.")); } + @ExceptionHandler + public ResponseEntity handleMethodArgumentTypeMismatchException( + final MethodArgumentTypeMismatchException e + ) { + final String errorMessage = String.format( + "%s는 %s 타입이 필요합니다.", + e.getPropertyName(), + e.getRequiredType().getSimpleName() + ); + log.warn("[" + e.getClass() + "] : " + errorMessage); + return ResponseEntity.badRequest() + .body(new ExceptionResponse(-9998, errorMessage)); + } + + @ExceptionHandler + public ResponseEntity handleMethodArgumentNotValidException( + final MethodArgumentNotValidException e + ) { + final List errorMessages = e.getBindingResult() + .getAllErrors() + .stream() + .map(error -> error.getDefaultMessage()) + .toList(); + log.warn("[" + e.getClass() + "] : " + errorMessages); + return ResponseEntity.badRequest() + .body(new ExceptionResponse(-9997, errorMessages.toString())); + } + @ExceptionHandler public ResponseEntity handleBadRequestException(final BadRequestException e) { log.warn("[" + e.getClass() + "] : " + e.getMessage()); diff --git a/backend/src/test/java/com/votogether/domain/post/controller/PostCommentControllerTest.java b/backend/src/test/java/com/votogether/domain/post/controller/PostCommentControllerTest.java new file mode 100644 index 000000000..2d1e89a39 --- /dev/null +++ b/backend/src/test/java/com/votogether/domain/post/controller/PostCommentControllerTest.java @@ -0,0 +1,117 @@ +package com.votogether.domain.post.controller; + +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; + +import com.votogether.domain.member.service.MemberService; +import com.votogether.domain.post.dto.request.CommentRegisterRequest; +import com.votogether.domain.post.service.PostCommentService; +import com.votogether.fixtures.MemberFixtures; +import com.votogether.global.jwt.TokenPayload; +import com.votogether.global.jwt.TokenProcessor; +import io.restassured.module.mockmvc.RestAssuredMockMvc; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullAndEmptySource; +import org.junit.jupiter.params.provider.ValueSource; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.web.context.WebApplicationContext; + +@WebMvcTest(PostCommentController.class) +class PostCommentControllerTest { + + @MockBean + PostCommentService postCommentService; + + @MockBean + MemberService memberService; + + @MockBean + TokenProcessor tokenProcessor; + + @BeforeEach + void setUp(final WebApplicationContext webApplicationContext) { + RestAssuredMockMvc.standaloneSetup(new PostCommentController(postCommentService)); + RestAssuredMockMvc.webAppContextSetup(webApplicationContext); + } + + @Nested + @DisplayName("게시글 댓글 등록 시 ") + class RegisterComment { + + @ParameterizedTest + @ValueSource(strings = {"@", "a", "가"}) + @DisplayName("ID로 변환할 수 없는 타입이라면 400을 응답한다.") + void invalidIDType(String id) throws Exception { + // given + TokenPayload tokenPayload = new TokenPayload(1L, 1L, 1L); + given(tokenProcessor.resolveToken(anyString())).willReturn("token"); + given(tokenProcessor.parseToken(anyString())).willReturn(tokenPayload); + given(memberService.findById(anyLong())).willReturn(MemberFixtures.MALE_20.get()); + + // when, then + RestAssuredMockMvc.given().log().all() + .headers(HttpHeaders.AUTHORIZATION, "Bearer token") + .when().post("/posts/{postId}/comments", id) + .then().log().all() + .status(HttpStatus.BAD_REQUEST) + .body("code", equalTo(-9998)) + .body("message", equalTo("postId는 Long 타입이 필요합니다.")); + } + + @ParameterizedTest + @NullAndEmptySource + @DisplayName("댓글 내용이 존재하지 않으면 400을 응답한다.") + void emptyContent(final String content) throws Exception { + // given + TokenPayload tokenPayload = new TokenPayload(1L, 1L, 1L); + given(tokenProcessor.resolveToken(anyString())).willReturn("token"); + given(tokenProcessor.parseToken(anyString())).willReturn(tokenPayload); + given(memberService.findById(anyLong())).willReturn(MemberFixtures.MALE_20.get()); + CommentRegisterRequest commentRegisterRequest = new CommentRegisterRequest(content); + + // when, then + RestAssuredMockMvc.given().log().all() + .headers(HttpHeaders.AUTHORIZATION, "Bearer token") + .contentType(MediaType.APPLICATION_JSON) + .body(commentRegisterRequest) + .when().post("/posts/{postId}/comments", 1) + .then().log().all() + .status(HttpStatus.BAD_REQUEST) + .body("code", equalTo(-9997)) + .body("message", containsString("댓글 내용은 존재해야 합니다.")); + } + + @Test + @DisplayName("댓글을 정상적으로 등록하면 201을 응답한다.") + void registerComment() throws Exception { + // given + TokenPayload tokenPayload = new TokenPayload(1L, 1L, 1L); + given(tokenProcessor.resolveToken(anyString())).willReturn("token"); + given(tokenProcessor.parseToken(anyString())).willReturn(tokenPayload); + given(memberService.findById(anyLong())).willReturn(MemberFixtures.MALE_20.get()); + CommentRegisterRequest commentRegisterRequest = new CommentRegisterRequest("댓글입니다."); + + // when, then + RestAssuredMockMvc.given().log().all() + .headers(HttpHeaders.AUTHORIZATION, "Bearer token") + .contentType(MediaType.APPLICATION_JSON) + .body(commentRegisterRequest) + .when().post("/posts/{postId}/comments", 1) + .then().log().all() + .status(HttpStatus.CREATED); + } + + } + +} From c8f173c3d6fafb591ebc10e88409cbab3798ce05 Mon Sep 17 00:00:00 2001 From: woo-chang Date: Thu, 27 Jul 2023 12:43:15 +0900 Subject: [PATCH 04/14] =?UTF-8?q?feat:=20(#128)=20Swagger=20Auth=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/votogether/config/OpenAPIConfig.java | 20 ++++++++++++++++++- .../java/com/votogether/global/jwt/Auth.java | 2 ++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/backend/src/main/java/com/votogether/config/OpenAPIConfig.java b/backend/src/main/java/com/votogether/config/OpenAPIConfig.java index 4519af3f7..96c603ebc 100644 --- a/backend/src/main/java/com/votogether/config/OpenAPIConfig.java +++ b/backend/src/main/java/com/votogether/config/OpenAPIConfig.java @@ -1,7 +1,12 @@ package com.votogether.config; +import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.security.SecurityRequirement; +import io.swagger.v3.oas.models.security.SecurityScheme; +import io.swagger.v3.oas.models.security.SecurityScheme.In; +import io.swagger.v3.oas.models.security.SecurityScheme.Type; import io.swagger.v3.oas.models.servers.Server; import java.util.List; import org.springframework.beans.factory.annotation.Value; @@ -37,9 +42,22 @@ public OpenAPI openAPI() { .version("v1.0.0") .description("보투게더 API"); + final SecurityScheme securityScheme = new SecurityScheme() + .type(Type.HTTP) + .in(In.HEADER) + .name("Authorization") + .scheme("bearer") + .bearerFormat("JWT") + .description("Bearer JWT"); + + final SecurityRequirement securityRequirement = new SecurityRequirement() + .addList("bearerAuth"); + return new OpenAPI() .info(info) - .servers(List.of(devServer, prodServer)); + .servers(List.of(devServer, prodServer)) + .components(new Components().addSecuritySchemes("bearerAuth", securityScheme)) + .security(List.of(securityRequirement)); } } diff --git a/backend/src/main/java/com/votogether/global/jwt/Auth.java b/backend/src/main/java/com/votogether/global/jwt/Auth.java index 0e014c0c9..ad622369c 100644 --- a/backend/src/main/java/com/votogether/global/jwt/Auth.java +++ b/backend/src/main/java/com/votogether/global/jwt/Auth.java @@ -1,10 +1,12 @@ package com.votogether.global.jwt; +import io.swagger.v3.oas.annotations.Hidden; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +@Hidden @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface Auth { From 84a9e3100d677547c6578a80695f8b932931b632 Mon Sep 17 00:00:00 2001 From: woo-chang Date: Thu, 27 Jul 2023 15:12:55 +0900 Subject: [PATCH 05/14] =?UTF-8?q?feat:=20(#128)=20Swagger=20=EB=AC=B8?= =?UTF-8?q?=EC=84=9C=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../post/controller/PostCommentController.java | 12 ++++++++++-- .../com/votogether/exception/ExceptionResponse.java | 10 +++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/backend/src/main/java/com/votogether/domain/post/controller/PostCommentController.java b/backend/src/main/java/com/votogether/domain/post/controller/PostCommentController.java index efe69de91..b793cf88f 100644 --- a/backend/src/main/java/com/votogether/domain/post/controller/PostCommentController.java +++ b/backend/src/main/java/com/votogether/domain/post/controller/PostCommentController.java @@ -3,8 +3,12 @@ import com.votogether.domain.member.entity.Member; import com.votogether.domain.post.dto.request.CommentRegisterRequest; import com.votogether.domain.post.service.PostCommentService; +import com.votogether.exception.ExceptionResponse; import com.votogether.global.jwt.Auth; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; @@ -29,12 +33,16 @@ public class PostCommentController { @Operation(summary = "게시글 댓글 작성", description = "게시글 댓글을 작성한다.") @ApiResponses({ @ApiResponse(responseCode = "200", description = "게시글 댓글 작성 성공"), - @ApiResponse(responseCode = "404", description = "존재하지 않는 게시글에 대한 댓글 작성") + @ApiResponse( + responseCode = "404", + description = "존재하지 않는 게시글에 대한 댓글 작성", + content = @Content(schema = @Schema(implementation = ExceptionResponse.class)) + ) }) @PostMapping("/{postId}/comments") public ResponseEntity registerComment( @Auth final Member member, - @PathVariable final Long postId, + @PathVariable @Parameter(description = "댓글 작성 게시글 ID") final Long postId, @Valid @RequestBody CommentRegisterRequest commentRegisterRequest ) { postCommentService.registerComment(member, postId, commentRegisterRequest); diff --git a/backend/src/main/java/com/votogether/exception/ExceptionResponse.java b/backend/src/main/java/com/votogether/exception/ExceptionResponse.java index adecbcfb2..3524982b6 100644 --- a/backend/src/main/java/com/votogether/exception/ExceptionResponse.java +++ b/backend/src/main/java/com/votogether/exception/ExceptionResponse.java @@ -1,6 +1,14 @@ package com.votogether.exception; -public record ExceptionResponse(int code, String message) { +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(description = "예외 발생 응답") +public record ExceptionResponse( + @Schema(description = "예외 코드", example = "-9999") + int code, + @Schema(description = "예외 메시지", example = "알 수 없는 서버 예외가 발생하였습니다.") + String message +) { public static ExceptionResponse from(final BaseException e) { return new ExceptionResponse(e.getCode(), e.getMessage()); From 9c7ba5107c50156dc8a5461c2d43791ed30ecd61 Mon Sep 17 00:00:00 2001 From: woo-chang Date: Thu, 27 Jul 2023 15:13:09 +0900 Subject: [PATCH 06/14] =?UTF-8?q?feat:=20(#128)=20Swagger=20=ED=99=98?= =?UTF-8?q?=EA=B2=BD=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/main/resources/application.yml | 5 +++++ backend/src/test/resources/application.yml | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index b9cccf11d..03b9e4fe2 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -25,6 +25,11 @@ logging: server: forward-headers-strategy: FRAMEWORK +springdoc: + swagger-ui: + enabled: ${SWAGGER_ENABLE} + default-produces-media-type: application/json;charset=UTF-8 + votogether: openapi: dev-url: http://localhost:8080 diff --git a/backend/src/test/resources/application.yml b/backend/src/test/resources/application.yml index dd3d86540..93a3ba5a2 100644 --- a/backend/src/test/resources/application.yml +++ b/backend/src/test/resources/application.yml @@ -1,3 +1,7 @@ +springdoc: + swagger-ui: + enabled: false + votogether: openapi: dev-url: http://localhost:8080 From d14f23a12aec524e19dfe3be8f0e1ea3b430aef9 Mon Sep 17 00:00:00 2001 From: woo-chang Date: Thu, 27 Jul 2023 17:56:41 +0900 Subject: [PATCH 07/14] =?UTF-8?q?refactor:=20(#128)=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=ED=95=98=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/post/service/PostCommentServiceTest.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/backend/src/test/java/com/votogether/domain/post/service/PostCommentServiceTest.java b/backend/src/test/java/com/votogether/domain/post/service/PostCommentServiceTest.java index ada57c0a9..c6af18e85 100644 --- a/backend/src/test/java/com/votogether/domain/post/service/PostCommentServiceTest.java +++ b/backend/src/test/java/com/votogether/domain/post/service/PostCommentServiceTest.java @@ -11,7 +11,6 @@ import com.votogether.domain.post.repository.CommentRepository; import com.votogether.domain.post.repository.PostRepository; import com.votogether.fixtures.MemberFixtures; -import jakarta.persistence.EntityManager; import java.time.LocalDateTime; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -20,9 +19,6 @@ @ServiceTest class PostCommentServiceTest { - @Autowired - EntityManager em; - @Autowired PostCommentService postCommentService; From d7bf9deb695663688b9a4eedf710410f54a16ee6 Mon Sep 17 00:00:00 2001 From: woo-chang Date: Thu, 27 Jul 2023 21:50:50 +0900 Subject: [PATCH 08/14] =?UTF-8?q?refactor:=20(#128)=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=EC=97=90=20=EC=82=AC=EC=9A=A9=EB=90=98=EB=8A=94=20?= =?UTF-8?q?=EA=B0=9D=EC=B2=B4=20=EC=B6=94=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/post/service/PostCommentService.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/backend/src/main/java/com/votogether/domain/post/service/PostCommentService.java b/backend/src/main/java/com/votogether/domain/post/service/PostCommentService.java index b48a377dd..aca52d893 100644 --- a/backend/src/main/java/com/votogether/domain/post/service/PostCommentService.java +++ b/backend/src/main/java/com/votogether/domain/post/service/PostCommentService.java @@ -26,12 +26,12 @@ public void registerComment( final Post post = postRepository.findById(postId) .orElseThrow(() -> new BadRequestException(PostExceptionType.POST_NOT_FOUND)); - post.addComment( - Comment.builder() - .member(member) - .content(commentRegisterRequest.content()) - .build() - ); + final Comment comment = Comment.builder() + .member(member) + .content(commentRegisterRequest.content()) + .build(); + + post.addComment(comment); } } From c8c4a51183cfac0fce21ad0b9df1db6c07fae70e Mon Sep 17 00:00:00 2001 From: woo-chang Date: Fri, 28 Jul 2023 11:03:10 +0900 Subject: [PATCH 09/14] =?UTF-8?q?fix:=20(#128)=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=EC=97=90=EC=84=9C=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EC=84=A4=EC=A0=95=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/test/resources/application.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/backend/src/test/resources/application.yml b/backend/src/test/resources/application.yml index 93a3ba5a2..dd3d86540 100644 --- a/backend/src/test/resources/application.yml +++ b/backend/src/test/resources/application.yml @@ -1,7 +1,3 @@ -springdoc: - swagger-ui: - enabled: false - votogether: openapi: dev-url: http://localhost:8080 From ebc28b9150880efe9aa0efdf2825aa6a5976f98c Mon Sep 17 00:00:00 2001 From: woo-chang Date: Fri, 28 Jul 2023 11:08:55 +0900 Subject: [PATCH 10/14] =?UTF-8?q?refactor:=20(#128)=20=EB=AA=85=ED=99=95?= =?UTF-8?q?=ED=95=9C=20=EC=9D=98=EB=AF=B8=EB=A5=BC=20=EA=B0=80=EC=A7=84=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=EB=AA=85=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/post/controller/PostCommentController.java | 4 ++-- .../votogether/domain/post/service/PostCommentService.java | 2 +- .../domain/post/controller/PostCommentControllerTest.java | 4 ++-- .../domain/post/service/PostCommentServiceTest.java | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/backend/src/main/java/com/votogether/domain/post/controller/PostCommentController.java b/backend/src/main/java/com/votogether/domain/post/controller/PostCommentController.java index b793cf88f..c591bc2ad 100644 --- a/backend/src/main/java/com/votogether/domain/post/controller/PostCommentController.java +++ b/backend/src/main/java/com/votogether/domain/post/controller/PostCommentController.java @@ -40,12 +40,12 @@ public class PostCommentController { ) }) @PostMapping("/{postId}/comments") - public ResponseEntity registerComment( + public ResponseEntity createComment( @Auth final Member member, @PathVariable @Parameter(description = "댓글 작성 게시글 ID") final Long postId, @Valid @RequestBody CommentRegisterRequest commentRegisterRequest ) { - postCommentService.registerComment(member, postId, commentRegisterRequest); + postCommentService.createComment(member, postId, commentRegisterRequest); return ResponseEntity.status(HttpStatus.CREATED).build(); } diff --git a/backend/src/main/java/com/votogether/domain/post/service/PostCommentService.java b/backend/src/main/java/com/votogether/domain/post/service/PostCommentService.java index aca52d893..141d2ba1a 100644 --- a/backend/src/main/java/com/votogether/domain/post/service/PostCommentService.java +++ b/backend/src/main/java/com/votogether/domain/post/service/PostCommentService.java @@ -18,7 +18,7 @@ public class PostCommentService { private final PostRepository postRepository; @Transactional - public void registerComment( + public void createComment( final Member member, final Long postId, final CommentRegisterRequest commentRegisterRequest diff --git a/backend/src/test/java/com/votogether/domain/post/controller/PostCommentControllerTest.java b/backend/src/test/java/com/votogether/domain/post/controller/PostCommentControllerTest.java index 2d1e89a39..887e3c85d 100644 --- a/backend/src/test/java/com/votogether/domain/post/controller/PostCommentControllerTest.java +++ b/backend/src/test/java/com/votogether/domain/post/controller/PostCommentControllerTest.java @@ -47,7 +47,7 @@ void setUp(final WebApplicationContext webApplicationContext) { @Nested @DisplayName("게시글 댓글 등록 시 ") - class RegisterComment { + class CreateComment { @ParameterizedTest @ValueSource(strings = {"@", "a", "가"}) @@ -94,7 +94,7 @@ void emptyContent(final String content) throws Exception { @Test @DisplayName("댓글을 정상적으로 등록하면 201을 응답한다.") - void registerComment() throws Exception { + void createComment() throws Exception { // given TokenPayload tokenPayload = new TokenPayload(1L, 1L, 1L); given(tokenProcessor.resolveToken(anyString())).willReturn("token"); diff --git a/backend/src/test/java/com/votogether/domain/post/service/PostCommentServiceTest.java b/backend/src/test/java/com/votogether/domain/post/service/PostCommentServiceTest.java index c6af18e85..56e116295 100644 --- a/backend/src/test/java/com/votogether/domain/post/service/PostCommentServiceTest.java +++ b/backend/src/test/java/com/votogether/domain/post/service/PostCommentServiceTest.java @@ -33,7 +33,7 @@ class PostCommentServiceTest { @Test @DisplayName("게시글에 댓글을 등록한다.") - void registerComment() { + void createComment() { // given Member member = memberRepository.save(MemberFixtures.MALE_20.get()); Post post = postRepository.save( @@ -46,7 +46,7 @@ void registerComment() { CommentRegisterRequest commentRegisterRequest = new CommentRegisterRequest("hello"); // when - postCommentService.registerComment(member, post.getId(), commentRegisterRequest); + postCommentService.createComment(member, post.getId(), commentRegisterRequest); // then assertThat(commentRepository.findAll()).hasSize(1); From 0e74bdb571abcd0aa9f7a4d8a4b3897cb447522a Mon Sep 17 00:00:00 2001 From: woo-chang Date: Fri, 28 Jul 2023 11:13:08 +0900 Subject: [PATCH 11/14] =?UTF-8?q?refactor:=20(#128)=20=EA=B2=8C=EC=8B=9C?= =?UTF-8?q?=EA=B8=80=EC=9D=B4=20=EC=A1=B4=EC=9E=AC=ED=95=98=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EC=9D=84=20=EB=95=8C=20=EC=98=88=EC=99=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../post/service/PostCommentService.java | 4 +- .../post/service/PostCommentServiceTest.java | 60 +++++++++++++------ 2 files changed, 43 insertions(+), 21 deletions(-) diff --git a/backend/src/main/java/com/votogether/domain/post/service/PostCommentService.java b/backend/src/main/java/com/votogether/domain/post/service/PostCommentService.java index 141d2ba1a..1550fda38 100644 --- a/backend/src/main/java/com/votogether/domain/post/service/PostCommentService.java +++ b/backend/src/main/java/com/votogether/domain/post/service/PostCommentService.java @@ -6,7 +6,7 @@ import com.votogether.domain.post.entity.comment.Comment; import com.votogether.domain.post.exception.PostExceptionType; import com.votogether.domain.post.repository.PostRepository; -import com.votogether.exception.BadRequestException; +import com.votogether.exception.NotFoundException; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -24,7 +24,7 @@ public void createComment( final CommentRegisterRequest commentRegisterRequest ) { final Post post = postRepository.findById(postId) - .orElseThrow(() -> new BadRequestException(PostExceptionType.POST_NOT_FOUND)); + .orElseThrow(() -> new NotFoundException(PostExceptionType.POST_NOT_FOUND)); final Comment comment = Comment.builder() .member(member) diff --git a/backend/src/test/java/com/votogether/domain/post/service/PostCommentServiceTest.java b/backend/src/test/java/com/votogether/domain/post/service/PostCommentServiceTest.java index 56e116295..e9b53ea99 100644 --- a/backend/src/test/java/com/votogether/domain/post/service/PostCommentServiceTest.java +++ b/backend/src/test/java/com/votogether/domain/post/service/PostCommentServiceTest.java @@ -1,6 +1,7 @@ package com.votogether.domain.post.service; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import com.votogether.ServiceTest; import com.votogether.domain.member.entity.Member; @@ -10,9 +11,11 @@ import com.votogether.domain.post.entity.PostBody; import com.votogether.domain.post.repository.CommentRepository; import com.votogether.domain.post.repository.PostRepository; +import com.votogether.exception.NotFoundException; import com.votogether.fixtures.MemberFixtures; import java.time.LocalDateTime; import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -31,25 +34,44 @@ class PostCommentServiceTest { @Autowired CommentRepository commentRepository; - @Test - @DisplayName("게시글에 댓글을 등록한다.") - void createComment() { - // given - Member member = memberRepository.save(MemberFixtures.MALE_20.get()); - Post post = postRepository.save( - Post.builder() - .member(member) - .postBody(PostBody.builder().title("title").content("content").build()) - .deadline(LocalDateTime.of(2100, 7, 12, 0, 0)) - .build() - ); - CommentRegisterRequest commentRegisterRequest = new CommentRegisterRequest("hello"); - - // when - postCommentService.createComment(member, post.getId(), commentRegisterRequest); - - // then - assertThat(commentRepository.findAll()).hasSize(1); + @Nested + @DisplayName("게시글 댓글 등록") + class CreateComment { + + @Test + @DisplayName("존재하지 않는 게시글이라면 예외를 던진다.") + void emptyPost() { + // given + Member member = memberRepository.save(MemberFixtures.MALE_20.get()); + CommentRegisterRequest commentRegisterRequest = new CommentRegisterRequest("hello"); + + // when, then + assertThatThrownBy(() -> postCommentService.createComment(member, -1L, commentRegisterRequest)) + .isInstanceOf(NotFoundException.class) + .hasMessage("해당 게시글이 존재하지 않습니다."); + } + + @Test + @DisplayName("게시글에 댓글을 등록한다.") + void createComment() { + // given + Member member = memberRepository.save(MemberFixtures.MALE_20.get()); + Post post = postRepository.save( + Post.builder() + .member(member) + .postBody(PostBody.builder().title("title").content("content").build()) + .deadline(LocalDateTime.of(2100, 7, 12, 0, 0)) + .build() + ); + CommentRegisterRequest commentRegisterRequest = new CommentRegisterRequest("hello"); + + // when + postCommentService.createComment(member, post.getId(), commentRegisterRequest); + + // then + assertThat(commentRepository.findAll()).hasSize(1); + } + } } From db959ef9cca127c012713f1272b1f9a32155f3ae Mon Sep 17 00:00:00 2001 From: woo-chang Date: Fri, 28 Jul 2023 11:25:42 +0900 Subject: [PATCH 12/14] =?UTF-8?q?refactor:=20(#128)=20applicaion/json=20?= =?UTF-8?q?=EA=B8=B0=EB=B3=B8=20=EC=84=A4=EC=A0=95=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/main/resources/application.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index 03b9e4fe2..1c49ccddc 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -28,7 +28,6 @@ server: springdoc: swagger-ui: enabled: ${SWAGGER_ENABLE} - default-produces-media-type: application/json;charset=UTF-8 votogether: openapi: From e2e044e1924b5cef0d6dd1fcdfc6d20759e0b9a3 Mon Sep 17 00:00:00 2001 From: woo-chang Date: Fri, 28 Jul 2023 13:18:05 +0900 Subject: [PATCH 13/14] =?UTF-8?q?refactor:=20(#128)=20=EC=BB=A4=EC=8A=A4?= =?UTF-8?q?=ED=85=80=20=EC=98=88=EC=99=B8=20=EC=B2=98=EB=A6=AC=20=EB=B0=A9?= =?UTF-8?q?=EC=8B=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../votogether/domain/post/entity/comment/Content.java | 5 +---- .../com/votogether/exception/BadRequestException.java | 4 ---- .../java/com/votogether/exception/BaseException.java | 9 ++------- .../java/com/votogether/exception/ExceptionResponse.java | 3 ++- .../domain/post/entity/comment/CommentTest.java | 2 +- 5 files changed, 6 insertions(+), 17 deletions(-) diff --git a/backend/src/main/java/com/votogether/domain/post/entity/comment/Content.java b/backend/src/main/java/com/votogether/domain/post/entity/comment/Content.java index 292ae1184..eb608524d 100644 --- a/backend/src/main/java/com/votogether/domain/post/entity/comment/Content.java +++ b/backend/src/main/java/com/votogether/domain/post/entity/comment/Content.java @@ -25,10 +25,7 @@ public Content(final String value) { private void validate(final String content) { if (content.length() > MAXIMUM_LENGTH) { - throw new BadRequestException( - CommentExceptionType.INVALID_CONTENT_LENGTH.getCode(), - String.format("댓글 길이는 최대 %d자까지 가능합니다.", MAXIMUM_LENGTH) - ); + throw new BadRequestException(CommentExceptionType.INVALID_CONTENT_LENGTH); } } diff --git a/backend/src/main/java/com/votogether/exception/BadRequestException.java b/backend/src/main/java/com/votogether/exception/BadRequestException.java index 2efa36d37..f58142bcc 100644 --- a/backend/src/main/java/com/votogether/exception/BadRequestException.java +++ b/backend/src/main/java/com/votogether/exception/BadRequestException.java @@ -6,8 +6,4 @@ public BadRequestException(final ExceptionType exceptionType) { super(exceptionType); } - public BadRequestException(final int code, final String message) { - super(code, message); - } - } diff --git a/backend/src/main/java/com/votogether/exception/BaseException.java b/backend/src/main/java/com/votogether/exception/BaseException.java index de12dc800..0c9754569 100644 --- a/backend/src/main/java/com/votogether/exception/BaseException.java +++ b/backend/src/main/java/com/votogether/exception/BaseException.java @@ -5,16 +5,11 @@ @Getter public class BaseException extends RuntimeException { - private final int code; + private final ExceptionType exceptionType; public BaseException(final ExceptionType exceptionType) { super(exceptionType.getMessage()); - this.code = exceptionType.getCode(); - } - - public BaseException(final int code, final String message) { - super(message); - this.code = code; + this.exceptionType = exceptionType; } } diff --git a/backend/src/main/java/com/votogether/exception/ExceptionResponse.java b/backend/src/main/java/com/votogether/exception/ExceptionResponse.java index 3524982b6..c501a7698 100644 --- a/backend/src/main/java/com/votogether/exception/ExceptionResponse.java +++ b/backend/src/main/java/com/votogether/exception/ExceptionResponse.java @@ -11,7 +11,8 @@ public record ExceptionResponse( ) { public static ExceptionResponse from(final BaseException e) { - return new ExceptionResponse(e.getCode(), e.getMessage()); + final ExceptionType exceptionType = e.getExceptionType(); + return new ExceptionResponse(exceptionType.getCode(), exceptionType.getMessage()); } } diff --git a/backend/src/test/java/com/votogether/domain/post/entity/comment/CommentTest.java b/backend/src/test/java/com/votogether/domain/post/entity/comment/CommentTest.java index a3af46bf5..70f6c2116 100644 --- a/backend/src/test/java/com/votogether/domain/post/entity/comment/CommentTest.java +++ b/backend/src/test/java/com/votogether/domain/post/entity/comment/CommentTest.java @@ -36,7 +36,7 @@ void invalidContentLength() { .build() ) .isInstanceOf(BadRequestException.class) - .hasMessage("댓글 길이는 최대 500자까지 가능합니다."); + .hasMessage("유효하지 않은 댓글 길이입니다."); } } From 32239f2c398a416abb0412121d195e207e1197a9 Mon Sep 17 00:00:00 2001 From: woo-chang Date: Fri, 28 Jul 2023 13:57:06 +0900 Subject: [PATCH 14/14] =?UTF-8?q?feat:=20(#128)=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=BF=BC=EB=A6=AC=20=ED=99=95=EC=9D=B8=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/test/resources/application.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/backend/src/test/resources/application.yml b/backend/src/test/resources/application.yml index dd3d86540..3ef527cc3 100644 --- a/backend/src/test/resources/application.yml +++ b/backend/src/test/resources/application.yml @@ -1,3 +1,14 @@ +spring: + jpa: + show-sql: true + properties: + hibernate: + format_sql: true + +logging: + level: + org.hibernate.orm.jdbc.bind: trace + votogether: openapi: dev-url: http://localhost:8080