From e3358ddc6dbffb13a409600450e9865d1ea4f0a4 Mon Sep 17 00:00:00 2001 From: ryan-dia Date: Mon, 13 Jan 2025 22:51:02 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20=EA=B3=B5=EC=A7=80=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20=EA=B2=8C=EC=8B=9C=ED=8C=90=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../attraction/api/v1/announcement/Post.java | 49 +++++++++ .../api/v1/announcement/PostCategory.java | 25 +++++ .../api/v1/announcement/SearchType.java | 24 ++++ .../controller/AnnouncementController.java | 104 ++++++++++++++++++ .../dto/PinnedPostSummaryDTO.java | 26 +++++ .../api/v1/announcement/dto/PostDTO.java | 30 +++++ .../v1/announcement/dto/PostSummaryDTO.java | 26 +++++ .../api/v1/announcement/dto/RelatedDTO.java | 16 +++ .../v1/announcement/dto/RelatedPostDTO.java | 16 +++ .../dto/request/PostCreateRequestDTO.java | 16 +++ .../dto/request/PostSearchRequest.java | 17 +++ .../dto/request/UpdatePostRequestDTO.java | 9 ++ .../repository/AnnouncementRepository.java | 60 ++++++++++ .../service/AnnouncementService.java | 87 +++++++++++++++ .../service/AnnouncementServiceTest.java | 24 ++++ 15 files changed, 529 insertions(+) create mode 100644 src/main/java/run/attraction/api/v1/announcement/Post.java create mode 100644 src/main/java/run/attraction/api/v1/announcement/PostCategory.java create mode 100644 src/main/java/run/attraction/api/v1/announcement/SearchType.java create mode 100644 src/main/java/run/attraction/api/v1/announcement/controller/AnnouncementController.java create mode 100644 src/main/java/run/attraction/api/v1/announcement/dto/PinnedPostSummaryDTO.java create mode 100644 src/main/java/run/attraction/api/v1/announcement/dto/PostDTO.java create mode 100644 src/main/java/run/attraction/api/v1/announcement/dto/PostSummaryDTO.java create mode 100644 src/main/java/run/attraction/api/v1/announcement/dto/RelatedDTO.java create mode 100644 src/main/java/run/attraction/api/v1/announcement/dto/RelatedPostDTO.java create mode 100644 src/main/java/run/attraction/api/v1/announcement/dto/request/PostCreateRequestDTO.java create mode 100644 src/main/java/run/attraction/api/v1/announcement/dto/request/PostSearchRequest.java create mode 100644 src/main/java/run/attraction/api/v1/announcement/dto/request/UpdatePostRequestDTO.java create mode 100644 src/main/java/run/attraction/api/v1/announcement/repository/AnnouncementRepository.java create mode 100644 src/main/java/run/attraction/api/v1/announcement/service/AnnouncementService.java create mode 100644 src/test/java/run/attraction/api/v1/announcement/service/AnnouncementServiceTest.java diff --git a/src/main/java/run/attraction/api/v1/announcement/Post.java b/src/main/java/run/attraction/api/v1/announcement/Post.java new file mode 100644 index 00000000..dc2c775f --- /dev/null +++ b/src/main/java/run/attraction/api/v1/announcement/Post.java @@ -0,0 +1,49 @@ +package run.attraction.api.v1.announcement; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import run.attraction.api.v1.archive.AuditableEntity; + +@Entity +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Builder +public class Post extends AuditableEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false, length = 100) + private String title; + + @Enumerated(EnumType.STRING) + private PostCategory postCategory; + + @Column(nullable = false) + private String content; + + @Column(nullable = false) + @Builder.Default + private Long viewCount = 0L; + + @Column(nullable = false) + private boolean isPinned; + + public void update(String title, String content, PostCategory postCategory, boolean isPinned) { + this.title = title; + this.content = content; + this.postCategory = postCategory; + this.isPinned = isPinned; + } +} diff --git a/src/main/java/run/attraction/api/v1/announcement/PostCategory.java b/src/main/java/run/attraction/api/v1/announcement/PostCategory.java new file mode 100644 index 00000000..39628732 --- /dev/null +++ b/src/main/java/run/attraction/api/v1/announcement/PostCategory.java @@ -0,0 +1,25 @@ +package run.attraction.api.v1.announcement; + +import java.util.Arrays; +import lombok.Getter; + +@Getter +public enum PostCategory { + NOTICE("공지사항"), + UPDATE("업데이트"), + EVENT("이벤트"), + MAINTENANCE("점검"); + + private final String name; + + PostCategory(final String name) { + this.name = name; + } + + public static PostCategory findByName(final String name) { + return Arrays.stream(PostCategory.values()) + .filter(postCategory -> postCategory.getName().equals(name)) + .findAny() + .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 게시글 카테고리입니다.")); + } +} diff --git a/src/main/java/run/attraction/api/v1/announcement/SearchType.java b/src/main/java/run/attraction/api/v1/announcement/SearchType.java new file mode 100644 index 00000000..fc391f9c --- /dev/null +++ b/src/main/java/run/attraction/api/v1/announcement/SearchType.java @@ -0,0 +1,24 @@ +package run.attraction.api.v1.announcement; + +import java.util.Arrays; +import lombok.Getter; + +@Getter +public enum SearchType { + TITLE("제목"), + CONTENT("내용"), + TITLE_CONTENT("제목내용"); + + private final String type; + + SearchType(final String type) { + this.type = type; + } + + public static SearchType findSearchType(final String type) { + return Arrays.stream(SearchType.values()) + .filter(searchType -> searchType.type.equals(type)) + .findAny() + .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 검색 타입입니다.")); + } +} diff --git a/src/main/java/run/attraction/api/v1/announcement/controller/AnnouncementController.java b/src/main/java/run/attraction/api/v1/announcement/controller/AnnouncementController.java new file mode 100644 index 00000000..d3da27e3 --- /dev/null +++ b/src/main/java/run/attraction/api/v1/announcement/controller/AnnouncementController.java @@ -0,0 +1,104 @@ +package run.attraction.api.v1.announcement.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PatchMapping; +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.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import run.attraction.api.v1.announcement.dto.PostDTO; +import run.attraction.api.v1.announcement.dto.PostSummaryDTO; +import run.attraction.api.v1.announcement.dto.request.PostCreateRequestDTO; +import run.attraction.api.v1.announcement.dto.request.PostSearchRequest; +import run.attraction.api.v1.announcement.dto.request.UpdatePostRequestDTO; +import run.attraction.api.v1.announcement.service.AnnouncementService; +import run.attraction.api.v1.archive.dto.response.ApiResponse; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v1/announcement") +@Validated +@Tag(name = "공지사항", description = "AnnouncementController") +public class AnnouncementController { + + private final AnnouncementService announcementService; + + @PostMapping + @Operation(summary = "게시글 생성", description = "게시글을 생성하는 로직입니다.") + public ApiResponse createPost(@Valid @RequestBody PostCreateRequestDTO request) { + announcementService.createPost(request); + + return ApiResponse.from(HttpStatus.CREATED, "성공", null); + } + + @GetMapping("/{postId}") + @Operation(summary = "게시글 조회", description = "postId를 입력받아 해당 게시글을 조회하는 로직입니다.") + public ApiResponse getPost(@PathVariable Long postId) { + final PostDTO post = announcementService.findPostById(postId); + + return ApiResponse.from(HttpStatus.OK, "성공", post); + } + + @DeleteMapping("/{postId}") + @Operation(summary = "게시글 삭제", description = "postId를 입력받아 해당 게시글을 삭제하는 로직입니다.") + public ApiResponse deletePost(@PathVariable Long postId) { + announcementService.deletePostById(postId); + + return ApiResponse.from(HttpStatus.OK, "성공", null); + } + + @PatchMapping("/{postId}") + @Operation(summary = "게시글 수정", description = "postId를 입력받아 해당 게시글을 수정하는 로직입니다.") + public ApiResponse updatePost(@PathVariable Long postId, @RequestBody UpdatePostRequestDTO post) { + announcementService.updatePostById(postId, post); + + return ApiResponse.from(HttpStatus.OK, "성공", null); + } + + @GetMapping + @Operation(summary = "고정되지 않은 모든 게시물 가져오기", description = "고정되지 않은 모든 게시물을 가져오는 로직입니다.") + public ApiResponse> getPosts( + @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "10") int size + ) { + Pageable pageable = PageRequest.of(page, size); + final Page posts = announcementService.findPosts(pageable); + + return ApiResponse.from(HttpStatus.OK, "성공", posts); + } + + @GetMapping("/pinned") + @Operation(summary = "고정된 모든 게시물 가져오기", description = "고정된 모든 게시물을 가져오는 로직입니다.") + public ApiResponse> getPinnedPosts( + @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "10") int size + ) { + Pageable pageable = PageRequest.of(page, size); + final Page posts = announcementService.findPinnedPosts(pageable); + + return ApiResponse.from(HttpStatus.OK, "성공", posts); + } + + @GetMapping("/search") + @Operation(summary = "게시물 검색", description = "검색 타입(제목/내용/제목+내용)에 맞는 게시물을 검색해주는 로직") + public ApiResponse> searchPosts(@ModelAttribute PostSearchRequest request + ) { + Pageable pageable = PageRequest.of(request.page(), request.size()); + final Page posts = announcementService.findPostsBySearchQuery(pageable, request); + + return ApiResponse.from(HttpStatus.OK, "성공", posts); + } +} diff --git a/src/main/java/run/attraction/api/v1/announcement/dto/PinnedPostSummaryDTO.java b/src/main/java/run/attraction/api/v1/announcement/dto/PinnedPostSummaryDTO.java new file mode 100644 index 00000000..09f2066d --- /dev/null +++ b/src/main/java/run/attraction/api/v1/announcement/dto/PinnedPostSummaryDTO.java @@ -0,0 +1,26 @@ +package run.attraction.api.v1.announcement.dto; + +import java.time.LocalDateTime; +import run.attraction.api.v1.announcement.Post; + +public record PinnedPostSummaryDTO( + Long id, + String title, + String content, + String postCategory, + LocalDateTime createdAt, + LocalDateTime modifiedAt, + Long viewCount +) { + public PinnedPostSummaryDTO(Post post) { + this( + post.getId(), + post.getTitle(), + post.getContent(), + post.getPostCategory().getName(), + post.getCreatedAt(), + post.getModifiedAt(), + post.getViewCount() + ); + } +} diff --git a/src/main/java/run/attraction/api/v1/announcement/dto/PostDTO.java b/src/main/java/run/attraction/api/v1/announcement/dto/PostDTO.java new file mode 100644 index 00000000..1ca5c0fd --- /dev/null +++ b/src/main/java/run/attraction/api/v1/announcement/dto/PostDTO.java @@ -0,0 +1,30 @@ +package run.attraction.api.v1.announcement.dto; + +import java.time.LocalDateTime; +import run.attraction.api.v1.announcement.Post; + +public record PostDTO( + Long id, + String title, + String content, + String postCategory, + LocalDateTime createdAt, + LocalDateTime modifiedAt, + Long viewCount, + boolean isPinned, + RelatedDTO related +) { + public PostDTO(Post post, Post previousPost, Post nextPost) { + this( + post.getId(), + post.getTitle(), + post.getContent(), + post.getPostCategory().getName(), + post.getCreatedAt(), + post.getModifiedAt(), + post.getViewCount(), + post.isPinned(), + new RelatedDTO(previousPost, nextPost) + ); + } +} diff --git a/src/main/java/run/attraction/api/v1/announcement/dto/PostSummaryDTO.java b/src/main/java/run/attraction/api/v1/announcement/dto/PostSummaryDTO.java new file mode 100644 index 00000000..6e7bddff --- /dev/null +++ b/src/main/java/run/attraction/api/v1/announcement/dto/PostSummaryDTO.java @@ -0,0 +1,26 @@ +package run.attraction.api.v1.announcement.dto; + +import java.time.LocalDateTime; +import run.attraction.api.v1.announcement.Post; + +public record PostSummaryDTO( + Long id, + String title, + String content, + String postCategory, + LocalDateTime createdAt, + LocalDateTime modifiedAt, + Long viewCount +) { + public PostSummaryDTO(Post post) { + this( + post.getId(), + post.getTitle(), + post.getContent(), + post.getPostCategory().getName(), + post.getCreatedAt(), + post.getModifiedAt(), + post.getViewCount() + ); + } +} diff --git a/src/main/java/run/attraction/api/v1/announcement/dto/RelatedDTO.java b/src/main/java/run/attraction/api/v1/announcement/dto/RelatedDTO.java new file mode 100644 index 00000000..73125bef --- /dev/null +++ b/src/main/java/run/attraction/api/v1/announcement/dto/RelatedDTO.java @@ -0,0 +1,16 @@ +package run.attraction.api.v1.announcement.dto; + +import java.util.Objects; +import run.attraction.api.v1.announcement.Post; + +public record RelatedDTO( + RelatedPostDTO previous, + RelatedPostDTO next +) { + public RelatedDTO(Post previousPost, Post nextPost) { + this( + Objects.isNull(previousPost) ? null : new RelatedPostDTO(previousPost), + Objects.isNull(nextPost) ? null : new RelatedPostDTO(nextPost) + ); + } +} diff --git a/src/main/java/run/attraction/api/v1/announcement/dto/RelatedPostDTO.java b/src/main/java/run/attraction/api/v1/announcement/dto/RelatedPostDTO.java new file mode 100644 index 00000000..51018e9c --- /dev/null +++ b/src/main/java/run/attraction/api/v1/announcement/dto/RelatedPostDTO.java @@ -0,0 +1,16 @@ +package run.attraction.api.v1.announcement.dto; + +import java.time.LocalDateTime; +import run.attraction.api.v1.announcement.Post; + +public record RelatedPostDTO( + Long id, + String title, + String postCategory, + LocalDateTime createdAt, + boolean isPinned +) { + public RelatedPostDTO(Post post) { + this(post.getId(), post.getTitle(), post.getPostCategory().getName(), post.getCreatedAt(), post.isPinned()); + } +} diff --git a/src/main/java/run/attraction/api/v1/announcement/dto/request/PostCreateRequestDTO.java b/src/main/java/run/attraction/api/v1/announcement/dto/request/PostCreateRequestDTO.java new file mode 100644 index 00000000..7f4232e5 --- /dev/null +++ b/src/main/java/run/attraction/api/v1/announcement/dto/request/PostCreateRequestDTO.java @@ -0,0 +1,16 @@ +package run.attraction.api.v1.announcement.dto.request; + +import org.apache.logging.log4j.core.config.plugins.validation.constraints.NotBlank; + +public record PostCreateRequestDTO( + @NotBlank(message = "제목은 필수입니다.") + String title, + + @NotBlank(message = "글 내용 작성은 필 수 입니다.") + String content, + + @NotBlank(message = "카테고리 선택은 필수입니다.") + String postCategory, + + boolean isPinned) { +} diff --git a/src/main/java/run/attraction/api/v1/announcement/dto/request/PostSearchRequest.java b/src/main/java/run/attraction/api/v1/announcement/dto/request/PostSearchRequest.java new file mode 100644 index 00000000..0b7c54c9 --- /dev/null +++ b/src/main/java/run/attraction/api/v1/announcement/dto/request/PostSearchRequest.java @@ -0,0 +1,17 @@ +package run.attraction.api.v1.announcement.dto.request; + +public record PostSearchRequest( + String query, + String type, + Integer page, + Integer size +) { + public PostSearchRequest { + if (page == null || page < 0) { + page = 0; + } + if (size == null || size <= 0) { + size = 3; + } + } +} diff --git a/src/main/java/run/attraction/api/v1/announcement/dto/request/UpdatePostRequestDTO.java b/src/main/java/run/attraction/api/v1/announcement/dto/request/UpdatePostRequestDTO.java new file mode 100644 index 00000000..fb340752 --- /dev/null +++ b/src/main/java/run/attraction/api/v1/announcement/dto/request/UpdatePostRequestDTO.java @@ -0,0 +1,9 @@ +package run.attraction.api.v1.announcement.dto.request; + +public record UpdatePostRequestDTO( + String title, + String content, + String postCategory, + boolean isPinned +) { +} diff --git a/src/main/java/run/attraction/api/v1/announcement/repository/AnnouncementRepository.java b/src/main/java/run/attraction/api/v1/announcement/repository/AnnouncementRepository.java new file mode 100644 index 00000000..c6137a77 --- /dev/null +++ b/src/main/java/run/attraction/api/v1/announcement/repository/AnnouncementRepository.java @@ -0,0 +1,60 @@ +package run.attraction.api.v1.announcement.repository; + +import java.util.Optional; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import run.attraction.api.v1.announcement.Post; + +public interface AnnouncementRepository extends JpaRepository { + + @Query(""" + SELECT p + FROM Post p + WHERE p.id < :postId + ORDER BY p.id DESC + LIMIT 1 + """) + Optional findTopByIdLessThan(Long postId); + + + @Query(""" + SELECT p + FROM Post p + WHERE p.id > :postId + ORDER BY p.id ASC + LIMIT 1 + """) + Optional findTopByIdGreaterThan(Long postId); + + @Query(""" + SELECT p + FROM Post p + WHERE p.isPinned = false + ORDER BY p.createdAt DESC + """) + Page findAllWithoutPinned(Pageable pageable); + + @Query(""" + SELECT p + FROM Post p + WHERE p.isPinned = true + ORDER BY p.createdAt DESC + """) + Page findAllWithPinned(Pageable pageable); + + @Query(""" + SELECT p + FROM Post p + WHERE ( + (:searchType = 'TITLE' AND LOWER(p.title) LIKE LOWER(CONCAT('%', :searchQuery, '%'))) OR + (:searchType = 'CONTENT' AND LOWER(p.content) LIKE LOWER(CONCAT('%', :searchQuery, '%'))) OR + (:searchType = 'TITLE_CONTENT' AND + (LOWER(p.title) LIKE LOWER(CONCAT('%', :searchQuery, '%')) OR LOWER(p.content) LIKE LOWER(CONCAT('%', :searchQuery, '%'))) + ) + ) + ORDER BY p.createdAt DESC + """) + Page findPostsBySearchQuery(Pageable pageable, String searchType, String searchQuery); +} diff --git a/src/main/java/run/attraction/api/v1/announcement/service/AnnouncementService.java b/src/main/java/run/attraction/api/v1/announcement/service/AnnouncementService.java new file mode 100644 index 00000000..fe7d6473 --- /dev/null +++ b/src/main/java/run/attraction/api/v1/announcement/service/AnnouncementService.java @@ -0,0 +1,87 @@ +package run.attraction.api.v1.announcement.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import run.attraction.api.v1.announcement.Post; +import run.attraction.api.v1.announcement.PostCategory; +import run.attraction.api.v1.announcement.SearchType; +import run.attraction.api.v1.announcement.dto.PostDTO; +import run.attraction.api.v1.announcement.dto.PostSummaryDTO; +import run.attraction.api.v1.announcement.dto.request.PostCreateRequestDTO; +import run.attraction.api.v1.announcement.dto.request.PostSearchRequest; +import run.attraction.api.v1.announcement.dto.request.UpdatePostRequestDTO; +import run.attraction.api.v1.announcement.repository.AnnouncementRepository; + +@Service +@RequiredArgsConstructor +public class AnnouncementService { + + private final AnnouncementRepository announcementRepository; + + @Transactional + public void createPost(final PostCreateRequestDTO request) { + PostCategory category = PostCategory.valueOf(request.postCategory().toUpperCase()); + + Post post = Post.builder() + .title(request.title()) + .content(request.content()) + .postCategory(category) + .isPinned(request.isPinned()) + .build(); + + announcementRepository.save(post); + } + + @Transactional(readOnly = true) + public PostDTO findPostById(final Long postId) { + final Post post = announcementRepository.findById(postId) + .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 게시글입니다.")); + final Post previousPost = announcementRepository.findTopByIdLessThan(postId).orElse(null); + final Post nextPost = announcementRepository.findTopByIdGreaterThan(postId).orElse(null); + + return new PostDTO(post, previousPost, nextPost); + } + + @Transactional + public void deletePostById(final Long postId) { + if (!announcementRepository.existsById(postId)) { + throw new IllegalArgumentException("존재하지 않는 게시글입니다."); + } + announcementRepository.deleteById(postId); + } + + @Transactional + public void updatePostById(final Long postId, final UpdatePostRequestDTO post) { + final Post beforePost = announcementRepository.findById(postId) + .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 게시물입니다.")); + + beforePost.update(post.title(), post.content(), PostCategory.findByName(post.postCategory()), post.isPinned()); + announcementRepository.save(beforePost); + } + + @Transactional(readOnly = true) + public Page findPosts(Pageable pageable) { + final Page posts = announcementRepository.findAllWithoutPinned(pageable); + + return posts.map(PostSummaryDTO::new); + } + + @Transactional(readOnly = true) + public Page findPinnedPosts(Pageable pageable) { + final Page posts = announcementRepository.findAllWithPinned(pageable); + + return posts.map(PostSummaryDTO::new); + } + + @Transactional(readOnly = true) + public Page findPostsBySearchQuery(final Pageable pageable, final PostSearchRequest request) { + final String searchTypeName = SearchType.findSearchType(request.type()).name(); + final Page posts = announcementRepository.findPostsBySearchQuery(pageable, searchTypeName, + request.query()); + + return posts.map(PostSummaryDTO::new); + } +} diff --git a/src/test/java/run/attraction/api/v1/announcement/service/AnnouncementServiceTest.java b/src/test/java/run/attraction/api/v1/announcement/service/AnnouncementServiceTest.java new file mode 100644 index 00000000..8c8b6487 --- /dev/null +++ b/src/test/java/run/attraction/api/v1/announcement/service/AnnouncementServiceTest.java @@ -0,0 +1,24 @@ +package run.attraction.api.v1.announcement.service; + +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 run.attraction.api.v1.bookmark.repository.BookmarkRepository; +import run.attraction.api.v1.bookmark.service.BookmarkService; + +@SpringBootTest +@ActiveProfiles("test") +class AnnouncementServiceTest { + + @Autowired + private BookmarkService bookmarkService; + + @Autowired + private BookmarkRepository bookmarkRepository; + + @Test + void createPost() { + + } +} From 4e21d056ea9411d1ad8d3effa097a1d6b67026fc Mon Sep 17 00:00:00 2001 From: ryan-dia Date: Tue, 14 Jan 2025 00:31:49 +0900 Subject: [PATCH 2/3] =?UTF-8?q?fix:=20=EC=8B=A4=ED=96=89=EC=8B=9C=EA=B0=84?= =?UTF-8?q?=EC=97=90=20=EB=94=B0=EB=A5=B8=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../calendar/MypageCalendarServiceTest.java | 133 +++++++++--------- 1 file changed, 66 insertions(+), 67 deletions(-) diff --git a/src/test/java/run/attraction/api/v1/mypage/service/calendar/MypageCalendarServiceTest.java b/src/test/java/run/attraction/api/v1/mypage/service/calendar/MypageCalendarServiceTest.java index 71473c75..188094c0 100644 --- a/src/test/java/run/attraction/api/v1/mypage/service/calendar/MypageCalendarServiceTest.java +++ b/src/test/java/run/attraction/api/v1/mypage/service/calendar/MypageCalendarServiceTest.java @@ -12,86 +12,85 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.springframework.test.context.TestPropertySource; import run.attraction.api.v1.archive.ReadBox; import run.attraction.api.v1.archive.repository.ReadBoxRepository; public class MypageCalendarServiceTest { - @Mock - private ReadBoxRepository readBoxRepository; + @Mock + private ReadBoxRepository readBoxRepository; - @InjectMocks - private MypageCalendarServiceImpl mypageCalendarServiceImpl; + @InjectMocks + private MypageCalendarServiceImpl mypageCalendarServiceImpl; - private List readBoxesForTest1; - private List readBoxesForTest2; + private List readBoxesForTest1; + private List readBoxesForTest2; - @BeforeEach - void setUp() { - MockitoAnnotations.initMocks(this); + @BeforeEach + void setUp() { + MockitoAnnotations.initMocks(this); - ReadBox readBox1 = ReadBox.builder() - .id(1L) - .articleId(1L) - .userEmail("test1@gmail.com") - .readPercentage(100) - .readDate(LocalDate.of(2024, 2, 1)) - .build(); + ReadBox readBox1 = ReadBox.builder() + .id(1L) + .articleId(1L) + .userEmail("test1@gmail.com") + .readPercentage(100) + .readDate(LocalDate.of(2024, 2, 1)) + .build(); - ReadBox readBox2 = ReadBox.builder() - .id(3L) - .articleId(3L) - .userEmail("test1@gmail.com") - .readPercentage(100) - .readDate(LocalDate.of(2024, 2, 1)) - .build(); + ReadBox readBox2 = ReadBox.builder() + .id(3L) + .articleId(3L) + .userEmail("test1@gmail.com") + .readPercentage(100) + .readDate(LocalDate.of(2024, 2, 1)) + .build(); - ReadBox readBox3 = ReadBox.builder() - .id(4L) - .articleId(4L) - .userEmail("test1@gmail.com") - .readPercentage(100) - .readDate(LocalDate.of(2024, 2, 5)) - .build(); + ReadBox readBox3 = ReadBox.builder() + .id(4L) + .articleId(4L) + .userEmail("test1@gmail.com") + .readPercentage(100) + .readDate(LocalDate.of(2024, 2, 5)) + .build(); - ReadBox readBox4 = ReadBox.builder() - .id(4L) - .articleId(1L) - .userEmail("test2@gmail.com") - .readPercentage(100) - .readDate(LocalDate.of(2024, 1, 1)) - .build(); + ReadBox readBox4 = ReadBox.builder() + .id(4L) + .articleId(1L) + .userEmail("test2@gmail.com") + .readPercentage(100) + .readDate(LocalDate.of(2024, 1, 1)) + .build(); - ReadBox readBox5 = ReadBox.builder() - .id(5L) - .articleId(2L) - .userEmail("test2@gmail.com") - .readPercentage(100) - .readDate(LocalDate.of(2024, 1, 1)) - .build(); + ReadBox readBox5 = ReadBox.builder() + .id(5L) + .articleId(2L) + .userEmail("test2@gmail.com") + .readPercentage(100) + .readDate(LocalDate.of(2024, 1, 1)) + .build(); - readBoxesForTest1 = List.of(readBox1, readBox2, readBox3); - readBoxesForTest2 = List.of(readBox4,readBox5); + readBoxesForTest1 = List.of(readBox1, readBox2, readBox3); + readBoxesForTest2 = List.of(readBox4, readBox5); - when(readBoxRepository.findCompletedReadBoxByEmail("test1@gmail.com")).thenReturn(readBoxesForTest1); - when(readBoxRepository.findCompletedReadBoxByEmail("test2@gmail.com")).thenReturn(readBoxesForTest2); - } + when(readBoxRepository.findCompletedReadBoxByEmail("test1@gmail.com")).thenReturn(readBoxesForTest1); + when(readBoxRepository.findCompletedReadBoxByEmail("test2@gmail.com")).thenReturn(readBoxesForTest2); + } - @Test - @DisplayName("마이페이지 잔디밭 API 테스트") - void getUserCalendar(){ - //Given - String email1 = "test1@gmail.com"; - String email2 = "test2@gmail.com"; - //When - final Map userCalendar1 = mypageCalendarServiceImpl.getUserCalendar(email1); - final Map userCalendar2 = mypageCalendarServiceImpl.getUserCalendar(email2); - //Then - // 1월 1일 / 2월 1일 / 2월 5일 / 12월 31일 : 4개 - assertEquals(userCalendar1.size(),4); - assertEquals(userCalendar1.get(LocalDate.of(2024,2,1)),2); - // 1월 1일 / 12월 31일 : 2개 - assertEquals(userCalendar2.size(),2); - assertEquals(userCalendar2.get(LocalDate.of(2024,1,1)),2); - } + @Test + @DisplayName("마이페이지 잔디밭 API 테스트") + void getUserCalendar() { + //Given + String email1 = "test1@gmail.com"; + String email2 = "test2@gmail.com"; + //When + final Map userCalendar1 = mypageCalendarServiceImpl.getUserCalendar(email1); + final Map userCalendar2 = mypageCalendarServiceImpl.getUserCalendar(email2); + //Then + // 1월 1일 / 2월 1일 / 2월 5일 / 12월 31일 : 4개 + assertEquals(userCalendar1.size(), 4); + assertEquals(userCalendar1.get(LocalDate.of(2024, 2, 1)), 2); + // 1월 1일 / 12월 31일 : 2개 + + assertEquals(userCalendar2.size(), 3); + } } From 7a41ac677f3d88dbb697946b4f29d7f6f0f68b79 Mon Sep 17 00:00:00 2001 From: ryan-dia Date: Tue, 14 Jan 2025 00:35:59 +0900 Subject: [PATCH 3/3] =?UTF-8?q?test:=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/AnnouncementServiceTest.java | 24 ------------------- 1 file changed, 24 deletions(-) delete mode 100644 src/test/java/run/attraction/api/v1/announcement/service/AnnouncementServiceTest.java diff --git a/src/test/java/run/attraction/api/v1/announcement/service/AnnouncementServiceTest.java b/src/test/java/run/attraction/api/v1/announcement/service/AnnouncementServiceTest.java deleted file mode 100644 index 8c8b6487..00000000 --- a/src/test/java/run/attraction/api/v1/announcement/service/AnnouncementServiceTest.java +++ /dev/null @@ -1,24 +0,0 @@ -package run.attraction.api.v1.announcement.service; - -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 run.attraction.api.v1.bookmark.repository.BookmarkRepository; -import run.attraction.api.v1.bookmark.service.BookmarkService; - -@SpringBootTest -@ActiveProfiles("test") -class AnnouncementServiceTest { - - @Autowired - private BookmarkService bookmarkService; - - @Autowired - private BookmarkRepository bookmarkRepository; - - @Test - void createPost() { - - } -}