diff --git a/src/test/java/leets/weeth/domain/board/application/usecase/NoticeUsecaseImplTest.java b/src/test/java/leets/weeth/domain/board/application/usecase/NoticeUsecaseImplTest.java index f03100a9..16634ecc 100644 --- a/src/test/java/leets/weeth/domain/board/application/usecase/NoticeUsecaseImplTest.java +++ b/src/test/java/leets/weeth/domain/board/application/usecase/NoticeUsecaseImplTest.java @@ -3,15 +3,22 @@ import leets.weeth.domain.board.application.dto.NoticeDTO; import leets.weeth.domain.board.application.mapper.NoticeMapper; import leets.weeth.domain.board.domain.entity.Notice; -import leets.weeth.domain.board.domain.test.fixture.NoticeFixture; +import leets.weeth.domain.board.domain.service.NoticeUpdateService; +import leets.weeth.domain.board.test.fixture.NoticeTestFixture; import leets.weeth.domain.board.domain.service.NoticeFindService; +import leets.weeth.domain.file.application.dto.request.FileSaveRequest; +import leets.weeth.domain.file.application.mapper.FileMapper; import leets.weeth.domain.file.domain.entity.File; +import leets.weeth.domain.file.domain.service.FileDeleteService; import leets.weeth.domain.file.domain.service.FileGetService; +import leets.weeth.domain.file.domain.service.FileSaveService; +import leets.weeth.domain.file.test.fixture.FileTestFixture; import leets.weeth.domain.user.domain.entity.User; import leets.weeth.domain.user.domain.entity.enums.Department; import leets.weeth.domain.user.domain.entity.enums.Position; import leets.weeth.domain.user.domain.entity.enums.Role; -import org.junit.jupiter.api.Disabled; +import leets.weeth.domain.user.test.fixture.UserTestFixture; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -29,17 +36,18 @@ @ExtendWith(MockitoExtension.class) class NoticeUsecaseImplTest { - @Mock - private NoticeFindService noticeFindService; + @InjectMocks private NoticeUsecaseImpl noticeUsecase; - @Mock - private FileGetService fileGetService; + @Mock private NoticeFindService noticeFindService; + @Mock private NoticeUpdateService noticeUpdateService; - @InjectMocks - private NoticeUsecaseImpl noticeUsecase; + @Mock private FileSaveService fileSaveService; + @Mock private FileGetService fileGetService; + @Mock private FileDeleteService fileDeleteService; + + @Mock private NoticeMapper noticeMapper; + @Mock private FileMapper fileMapper; - @Mock - private NoticeMapper noticeMapper; @Test void 공지사항이_최신순으로_정렬되는지() { @@ -54,7 +62,7 @@ class NoticeUsecaseImplTest { List notices = new ArrayList<>(); for(int i = 0; i<5; i++){ - Notice notice = NoticeFixture.createNotice("공지" + i, user); + Notice notice = NoticeTestFixture.createNotice("공지" + i, user); ReflectionTestUtils.setField(notice, "id", (long) i + 1); notices.add(notice); } @@ -98,7 +106,6 @@ class NoticeUsecaseImplTest { assertThat(noticeResponses.hasNext()).isTrue(); verify(noticeFindService, times(1)).findRecentNotices(pageable); - } @Test @@ -114,12 +121,12 @@ class NoticeUsecaseImplTest { List notices = new ArrayList<>(); for(int i = 0; i<3; i++){ - Notice notice = NoticeFixture.createNotice("공지" + i, user); + Notice notice = NoticeTestFixture.createNotice("공지" + i, user); ReflectionTestUtils.setField(notice, "id", (long) i + 1); notices.add(notice); } for(int i = 3; i<6; i++){ - Notice notice = NoticeFixture.createNotice("검색" + i, user); + Notice notice = NoticeTestFixture.createNotice("검색" + i, user); ReflectionTestUtils.setField(notice, "id", (long) i + 1); notices.add(notice); } @@ -182,13 +189,60 @@ class NoticeUsecaseImplTest { verify(noticeFindService, times(1)).search("검색", pageable); } - @Disabled("TODO: update 기능 테스트 구현 필요") @Test - void update() { + @DisplayName("공지사항 수정 시 기존 파일 삭제 후 새 파일로 업데이트된다") + void update_replacesOldFilesWithNewFiles() { + // given + Long noticeId = 1L; + Long userId = 1L; + + User user = UserTestFixture.createActiveUser1(userId); + Notice notice = NoticeTestFixture.createNotice(noticeId, "기존 제목", user); + + File oldFile = FileTestFixture.createFile(1L, "old.pdf", "https://example.com/old.pdf", notice); + List oldFiles = List.of(oldFile); + + NoticeDTO.Update dto = new NoticeDTO.Update("수정된 제목", "수정된 내용", + List.of(new FileSaveRequest("new.pdf", "https://example.com/new.pdf"))); + + File newFile = FileTestFixture.createFile(2L, "new.pdf", "https://example.com/new.pdf", notice); + List newFiles = List.of(newFile); + + NoticeDTO.SaveResponse expectedResponse = new NoticeDTO.SaveResponse(noticeId); + + given(noticeFindService.find(noticeId)).willReturn(notice); + given(fileGetService.findAllByNotice(noticeId)).willReturn(oldFiles); + given(fileMapper.toFileList(dto.files(), notice)).willReturn(newFiles); + given(noticeMapper.toSaveResponse(notice)).willReturn(expectedResponse); + + // when + NoticeDTO.SaveResponse response = noticeUsecase.update(noticeId, dto, userId); + + // then + assertThat(response).isEqualTo(expectedResponse); + + verify(noticeFindService).find(noticeId); + verify(fileGetService).findAllByNotice(noticeId); + verify(fileDeleteService).delete(oldFiles); + verify(fileMapper).toFileList(dto.files(), notice); + verify(fileSaveService).save(newFiles); + verify(noticeUpdateService).update(notice, dto); } - @Disabled("TODO: delete 기능 테스트 구현 필요") @Test - void delete() { + @DisplayName("공지사항 엔티티 update() 호출 시 제목과 내용이 변경된다") + void update_updatesTitleAndContent() { + // given + Long userId = 1L; + User user = UserTestFixture.createActiveUser1(userId); + Notice notice = NoticeTestFixture.createNotice(1L, "기존 제목", user); + NoticeDTO.Update dto = new NoticeDTO.Update("수정된 제목", "수정된 내용", List.of()); + + // when + notice.update(dto); + + // then + assertThat(notice.getTitle()).isEqualTo(dto.title()); + assertThat(notice.getContent()).isEqualTo(dto.content()); } } diff --git a/src/test/java/leets/weeth/domain/board/application/usecase/PostUseCaseImplTest.java b/src/test/java/leets/weeth/domain/board/application/usecase/PostUseCaseImplTest.java new file mode 100644 index 00000000..b7612d9a --- /dev/null +++ b/src/test/java/leets/weeth/domain/board/application/usecase/PostUseCaseImplTest.java @@ -0,0 +1,280 @@ +package leets.weeth.domain.board.application.usecase; + +import leets.weeth.domain.board.application.dto.PartPostDTO; +import leets.weeth.domain.board.application.dto.PostDTO; +import leets.weeth.domain.board.application.exception.CategoryAccessDeniedException; +import leets.weeth.domain.board.application.mapper.PostMapper; +import leets.weeth.domain.board.domain.entity.Post; +import leets.weeth.domain.board.domain.entity.enums.Category; +import leets.weeth.domain.board.domain.entity.enums.Part; +import leets.weeth.domain.board.domain.service.PostDeleteService; +import leets.weeth.domain.board.domain.service.PostFindService; +import leets.weeth.domain.board.domain.service.PostSaveService; +import leets.weeth.domain.board.domain.service.PostUpdateService; +import leets.weeth.domain.board.test.fixture.PostTestFixture; +import leets.weeth.domain.comment.application.mapper.CommentMapper; +import leets.weeth.domain.file.application.mapper.FileMapper; +import leets.weeth.domain.file.domain.entity.File; +import leets.weeth.domain.file.domain.service.FileDeleteService; +import leets.weeth.domain.file.domain.service.FileGetService; +import leets.weeth.domain.file.domain.service.FileSaveService; +import leets.weeth.domain.file.test.fixture.FileTestFixture; +import leets.weeth.domain.user.domain.entity.Cardinal; +import leets.weeth.domain.user.domain.entity.User; +import leets.weeth.domain.user.domain.service.CardinalGetService; +import leets.weeth.domain.user.domain.service.UserCardinalGetService; +import leets.weeth.domain.user.domain.service.UserGetService; +import leets.weeth.domain.user.test.fixture.CardinalTestFixture; +import leets.weeth.domain.user.test.fixture.UserTestFixture; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.data.domain.*; + +import java.util.List; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThatCode; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.BDDMockito.*; +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + +@ExtendWith(MockitoExtension.class) +class PostUseCaseImplTest { + + @InjectMocks private PostUseCaseImpl postUseCase; + + @Mock private PostSaveService postSaveService; + @Mock private PostFindService postFindService; + @Mock private PostUpdateService postUpdateService; + @Mock private PostDeleteService postDeleteService; + + @Mock private UserGetService userGetService; + @Mock private UserCardinalGetService userCardinalGetService; + @Mock private CardinalGetService cardinalGetService; + + @Mock private FileSaveService fileSaveService; + @Mock private FileGetService fileGetService; + @Mock private FileDeleteService fileDeleteService; + + @Mock private PostMapper mapper; + @Mock private FileMapper fileMapper; + @Mock private CommentMapper commentMapper; + + + @Test + @DisplayName("교육 게시글 저장 성공") + void saveEducation() { + Long userId = 1L; + long postId = 1L; + // given + PostDTO.SaveEducation request = new PostDTO.SaveEducation("제목1", "내용", + List.of(Part.BE), 1, List.of()); + + User user = UserTestFixture.createActiveUser1(1L); + Post post = PostTestFixture.createPost(postId, "제목1", Category.Education); + + given(userGetService.find(userId)).willReturn(user); + given(mapper.fromEducationDto(request, user)).willReturn(post); + given(postSaveService.save(post)).willReturn(post); + given(fileMapper.toFileList(request.files(), post)).willReturn(List.of()); + given(mapper.toSaveResponse(post)).willReturn(new PostDTO.SaveResponse(postId)); + + // when + PostDTO.SaveResponse response = postUseCase.saveEducation(request, userId); + + // then + assertThat(response.id()).isEqualTo(postId); + verify(userGetService).find(userId); + verify(postSaveService).save(post); + verify(mapper).toSaveResponse(post); + + } + + @Test + @DisplayName("관리자 권한이 없는 사용자가 교육 게시글 생성 시 예외를 던진다") + void saveEducation_unauthorizedUser_throwsException(){ + Long userId = 1L; + PostDTO.Save request = new PostDTO.Save("제목", "내용", Category.Education, + null, 1, Part.BE, 1, List.of()); + User user = UserTestFixture.createActiveUser1(1L); + + given(userGetService.find(userId)).willReturn(user); + + // when & then + assertThrows(CategoryAccessDeniedException.class, () -> postUseCase.save(request, userId)); + + } + + @Test + @DisplayName("특정 파트와 주차 조건으로 게시글 목록 조회 성공") + void findPartPosts_success() { + // given + PartPostDTO dto = new PartPostDTO( + Part.BE, + Category.Education, + 1, + 2, + "스터디1" + ); + + int pageNumber = 0; + int pageSize = 5; + User user = UserTestFixture.createActiveUser1(); + + Post post1 = PostTestFixture.createEducationPost(1L, user, "게시글1", Category.Education, List.of(Part.BE), + 1, 1); + Post post2 = PostTestFixture.createEducationPost(2L, user, "게시글2", Category.Education, List.of(Part.BE), + 1, 2); + + List postList = List.of(post2); + Slice postSlice = new SliceImpl<>(postList); + + PostDTO.ResponseAll response2 = PostTestFixture.createResponseAll(post2); + + given(postFindService.findByPartAndOptionalFilters( + dto.part(), + dto.category(), + dto.cardinalNumber(), + dto.studyName(), + dto.week(), + PageRequest.of(pageNumber, pageSize, Sort.by(Sort.Direction.DESC, "id")) + )).willReturn(postSlice); + + given(mapper.toAll(post2, false)).willReturn(response2); + + // when + Slice result = postUseCase.findPartPosts(dto, pageNumber, pageSize); + + // then + // 2주차 게시글만 포함되어 있어야 함 + assertThat(result).isNotNull(); + assertThat(result.getContent()).hasSize(1); + + PostDTO.ResponseAll first = result.getContent().get(0); + + assertThat(first.title()).isEqualTo("게시글2"); + assertThat(first.hasFile()).isFalse(); + + verify(postFindService).findByPartAndOptionalFilters( + dto.part(), + dto.category(), + dto.cardinalNumber(), + dto.studyName(), + dto.week(), + PageRequest.of(pageNumber, pageSize, Sort.by(Sort.Direction.DESC, "id")) + ); + } + + @Test + @DisplayName("관리자 권한 사용자가 교육 게시글 목록 조회 시 성공적으로 반환한다") + void findEducationPosts_success_adminUser() { + // given + Long userId = 1L; + Part part = Part.BE; + Integer cardinalNumber = 1; + int pageNumber = 0; + int pageSize = 5; + + User adminUser = UserTestFixture.createAdmin(userId); + + Post post1 = PostTestFixture.createEducationPost(1L, adminUser, "교육글1", Category.Education, List.of(Part.BE), 1, 1); + Post post2 = PostTestFixture.createEducationPost(2L, adminUser, "교육글2", Category.Education, List.of(Part.BE), 1, 2); + List postList = List.of(post1, post2); + Slice postSlice = new SliceImpl<>(postList); + + PostDTO.ResponseEducationAll response1 = PostTestFixture.createResponseEducationAll(post1, false); + PostDTO.ResponseEducationAll response2 = PostTestFixture.createResponseEducationAll(post2, false); + + given(userGetService.find(userId)).willReturn(adminUser); + given(postFindService.findByCategory(part, Category.Education, cardinalNumber, pageNumber, pageSize)) + .willReturn(postSlice); + given(mapper.toEducationAll(post1, false)).willReturn(response1); + given(mapper.toEducationAll(post2, false)).willReturn(response2); + + // when + Slice result = + postUseCase.findEducationPosts(userId, part, cardinalNumber, pageNumber, pageSize); + + // then + assertThat(result).isNotNull(); + assertThat(result.getContent()).hasSize(2); + assertThat(result.getContent()) + .extracting(PostDTO.ResponseEducationAll::title) + .containsExactly("교육글1", "교육글2"); + + verify(postFindService).findByCategory(part, Category.Education, cardinalNumber, pageNumber, pageSize); + verify(mapper).toEducationAll(post1, false); + verify(mapper).toEducationAll(post2, false); + } + + @Test + @DisplayName("스터디가 없을 시 예외가 발생하지 않는다") + void findStudyNames_noStudies_doesNotThrowException() { + Part part = Part.BE; + List emptyNames = List.of(); + + PostDTO.ResponseStudyNames expectedResponse = new PostDTO.ResponseStudyNames(emptyNames); + + given(postFindService.findByPart(part)).willReturn(emptyNames); + given(mapper.toStudyNames(emptyNames)).willReturn(expectedResponse); + + // when & then + assertThatCode(() -> postUseCase.findStudyNames(part)) + .doesNotThrowAnyException(); + + verify(postFindService).findByPart(part); + verify(mapper).toStudyNames(emptyNames); + } + + @Test + @DisplayName("본인이 속하지 않은 교육 자료를 검색하면 빈 리스트를 반환한다") + void findEducationPosts_whenUserNotInCardinal_returnsEmptyList() { + // given + Long userId = 1L; + Part part = Part.BE; + Integer cardinalNumber = 3; + int pageNumber = 0; + int pageSize = 5; + + User user = UserTestFixture.createActiveUser1(userId); + + Cardinal cardinal = CardinalTestFixture.createCardinal(1, 2025, 1); + + given(userGetService.find(userId)).willReturn(user); + given(cardinalGetService.findByUserSide(cardinalNumber)).willReturn(cardinal); + given(userCardinalGetService.notContains(user, cardinal)).willReturn(true); + + // when + Slice result = + postUseCase.findEducationPosts(userId, part, cardinalNumber, pageNumber, pageSize); + + // then + assertThat(result).isNotNull(); + assertThat(result.getContent()).isEmpty(); + assertThat(result.hasNext()).isFalse(); + + verify(userGetService).find(userId); + verify(cardinalGetService).findByUserSide(cardinalNumber); + verify(userCardinalGetService).notContains(user, cardinal); + verify(postFindService, never()).findEducationByCardinal(any(), anyInt(), any(Pageable.class)); + } + + @Test + @DisplayName("파일이 존재하는 경우 true를 반환한다") + void fileExists_returnsTrue() { + // given + Long postId = 1L; + File file = FileTestFixture.createFile(postId, "파일1", "url1"); + + given(fileGetService.findAllByPost(postId)).willReturn(List.of(file)); + // when + boolean fileExists = postUseCase.checkFileExistsByPost(postId); + + // then + assertThat(fileExists).isTrue(); + verify(fileGetService).findAllByPost(postId); + } +} diff --git a/src/test/java/leets/weeth/domain/board/domain/repository/NoticeRepositoryTest.java b/src/test/java/leets/weeth/domain/board/domain/repository/NoticeRepositoryTest.java index 2c017a48..9a2a5fbb 100644 --- a/src/test/java/leets/weeth/domain/board/domain/repository/NoticeRepositoryTest.java +++ b/src/test/java/leets/weeth/domain/board/domain/repository/NoticeRepositoryTest.java @@ -2,7 +2,7 @@ import leets.weeth.config.TestContainersConfig; import leets.weeth.domain.board.domain.entity.Notice; -import leets.weeth.domain.board.domain.test.fixture.NoticeFixture; +import leets.weeth.domain.board.test.fixture.NoticeTestFixture; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; @@ -31,7 +31,7 @@ class NoticeRepositoryTest { // given List notices = new ArrayList<>(); for(int i = 0; i<5; i++){ - Notice notice = NoticeFixture.createNotice("공지" + i); + Notice notice = NoticeTestFixture.createNotice("공지" + i); notices.add(notice); } @@ -60,9 +60,9 @@ class NoticeRepositoryTest { for(int i = 0; i<6; i++){ Notice notice; if(i % 2 == 0){ - notice = NoticeFixture.createNotice("공지" + i); + notice = NoticeTestFixture.createNotice("공지" + i); } else{ - notice = NoticeFixture.createNotice("검색" + i); + notice = NoticeTestFixture.createNotice("검색" + i); } notices.add(notice); } diff --git a/src/test/java/leets/weeth/domain/board/domain/test/fixture/NoticeFixture.java b/src/test/java/leets/weeth/domain/board/domain/test/fixture/NoticeFixture.java deleted file mode 100644 index 5bd9e00e..00000000 --- a/src/test/java/leets/weeth/domain/board/domain/test/fixture/NoticeFixture.java +++ /dev/null @@ -1,23 +0,0 @@ -package leets.weeth.domain.board.domain.test.fixture; - -import leets.weeth.domain.board.domain.entity.Notice; -import leets.weeth.domain.user.domain.entity.User; - -public class NoticeFixture { - public static Notice createNotice(String title, User user){ - return Notice.builder() - .title(title) - .content("내용") - .user(user) - .commentCount(0) - .build(); - } - - public static Notice createNotice(String title){ - return Notice.builder() - .title(title) - .content("내용") - .commentCount(0) - .build(); - } -} diff --git a/src/test/java/leets/weeth/domain/board/test/fixture/NoticeTestFixture.java b/src/test/java/leets/weeth/domain/board/test/fixture/NoticeTestFixture.java new file mode 100644 index 00000000..870a626d --- /dev/null +++ b/src/test/java/leets/weeth/domain/board/test/fixture/NoticeTestFixture.java @@ -0,0 +1,48 @@ +package leets.weeth.domain.board.test.fixture; + +import leets.weeth.domain.board.domain.entity.Notice; +import leets.weeth.domain.user.domain.entity.User; + +import java.util.ArrayList; + +public class NoticeTestFixture { + public static Notice createNotice(String title, User user){ + return Notice.builder() + .title(title) + .content("내용") + .user(user) + .comments(new ArrayList<>()) + .commentCount(0) + .build(); + } + + public static Notice createNotice(Long id, String title){ + return Notice.builder() + .id(id) + .title(title) + .content("내용") + .comments(new ArrayList<>()) + .commentCount(0) + .build(); + } + + public static Notice createNotice(Long id, String title, User user){ + return Notice.builder() + .id(id) + .title(title) + .content("내용") + .user(user) + .comments(new ArrayList<>()) + .commentCount(0) + .build(); + } + + public static Notice createNotice(String title){ + return Notice.builder() + .title(title) + .content("내용") + .comments(new ArrayList<>()) + .commentCount(0) + .build(); + } +} diff --git a/src/test/java/leets/weeth/domain/board/test/fixture/PostTestFixture.java b/src/test/java/leets/weeth/domain/board/test/fixture/PostTestFixture.java new file mode 100644 index 00000000..996d8bdb --- /dev/null +++ b/src/test/java/leets/weeth/domain/board/test/fixture/PostTestFixture.java @@ -0,0 +1,75 @@ +package leets.weeth.domain.board.test.fixture; + +import leets.weeth.domain.board.application.dto.PostDTO; +import leets.weeth.domain.board.domain.entity.Post; +import leets.weeth.domain.board.domain.entity.enums.Category; +import leets.weeth.domain.board.domain.entity.enums.Part; +import leets.weeth.domain.user.domain.entity.User; +import leets.weeth.domain.user.domain.entity.enums.Role; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +public class PostTestFixture { + public static Post createPost(Long id, String title, Category category){ + return Post.builder() + .id(id) + .title(title) + .content("내용") + .comments(new ArrayList<>()) + .commentCount(0) + .category(category) + .build(); + } + + public static Post createEducationPost(Long id, User user, String title, Category category, List parts, + int cardinalNumber, int week){ + return Post.builder() + .id(id) + .user(user) + .title(title) + .content("내용") + .parts(parts) + .cardinalNumber(cardinalNumber) + .week(week) + .commentCount(0) + .category(Category.Education) + .comments(new ArrayList<>()) + .build(); + } + + public static PostDTO.ResponseAll createResponseAll(Post post){ + return PostDTO.ResponseAll.builder() + .id(post.getId()) + .part(post.getPart()) + .role(Role.USER) + .title(post.getTitle()) + .content(post.getContent()) + .studyName(post.getStudyName()) + .week(post.getWeek()) + .time(LocalDateTime.now()) + .commentCount(post.getCommentCount()) + .hasFile(false) + .isNew(false) + .build(); + } + + public static PostDTO.ResponseEducationAll createResponseEducationAll(Post post, boolean fileExists) { + return PostDTO.ResponseEducationAll.builder() + .id(post.getId()) + .name(post.getUser().getName()) + .parts(post.getParts()) + .position(post.getUser().getPosition()) + .role(post.getUser().getRole()) + .title(post.getTitle()) + .content(post.getContent()) + .time(post.getCreatedAt()) + .commentCount(post.getCommentCount()) + .hasFile(fileExists) + .isNew(false) + .build(); + } + + +} diff --git a/src/test/java/leets/weeth/domain/comment/application/usecase/NoticeCommentUsecaseImplTest.java b/src/test/java/leets/weeth/domain/comment/application/usecase/NoticeCommentUsecaseImplTest.java new file mode 100644 index 00000000..3b146690 --- /dev/null +++ b/src/test/java/leets/weeth/domain/comment/application/usecase/NoticeCommentUsecaseImplTest.java @@ -0,0 +1,133 @@ +package leets.weeth.domain.comment.application.usecase; + +import leets.weeth.domain.board.domain.entity.Notice; +import leets.weeth.domain.board.domain.service.NoticeFindService; +import leets.weeth.domain.board.test.fixture.NoticeTestFixture; +import leets.weeth.domain.comment.application.dto.CommentDTO; +import leets.weeth.domain.comment.application.mapper.CommentMapper; +import leets.weeth.domain.comment.domain.entity.Comment; +import leets.weeth.domain.comment.domain.service.CommentFindService; +import leets.weeth.domain.comment.domain.service.CommentSaveService; +import leets.weeth.domain.comment.test.fixture.CommentTestFixture; +import leets.weeth.domain.file.application.mapper.FileMapper; +import leets.weeth.domain.file.domain.service.FileSaveService; +import leets.weeth.domain.user.application.exception.UserNotMatchException; +import leets.weeth.domain.user.domain.entity.User; +import leets.weeth.domain.user.domain.service.UserGetService; +import leets.weeth.domain.user.test.fixture.UserTestFixture; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.BDDMockito.*; +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + +@ExtendWith(MockitoExtension.class) +class NoticeCommentUsecaseImplTest { + @InjectMocks NoticeCommentUsecaseImpl noticeCommentUsecase; + + @Mock CommentSaveService commentSaveService; + @Mock CommentFindService commentFindService; + + @Mock FileSaveService fileSaveService; + @Mock FileMapper fileMapper; + + @Mock NoticeFindService noticeFindService; + + @Mock UserGetService userGetService; + @Mock CommentMapper commentMapper; + + @Test + @DisplayName("부모 댓글이 없는 공지사항 댓글 작성") + void saveNoticeComment() { + Long userId = 1L; + Long noticeId = 1L; + Long commentId = 1L; + // given + User user = UserTestFixture.createActiveUser1(1L); + Notice notice = NoticeTestFixture.createNotice(noticeId, "제목1"); + + CommentDTO.Save dto = new CommentDTO.Save(null, "댓글1", List.of()); + + Comment comment = CommentTestFixture.createComment(commentId, dto.content(), user, notice); + + given(commentMapper.fromCommentDto(dto, notice, user, null)).willReturn(comment); + given(userGetService.find(user.getId())).willReturn(user); + given(noticeFindService.find(notice.getId())).willReturn(notice); + given(fileMapper.toFileList(dto.files(), comment)).willReturn(List.of()); + + // when + noticeCommentUsecase.saveNoticeComment(dto, noticeId, userId); + + // then + verify(userGetService).find(userId); + verify(noticeFindService).find(noticeId); + verify(commentSaveService).save(comment); + + assertThat(notice.getComments()).contains(comment); + + } + + @Test + @DisplayName("부모 댓글이 있는 경우 공지사항 댓글 작성") + void saveChildNoticeComment() { + Long userId = 1L; + Long noticeId = 1L; + Long parentCommentId = 1L; + Long childCommentId = 2L; + // given + User user = UserTestFixture.createActiveUser1(parentCommentId); + Notice notice = NoticeTestFixture.createNotice(noticeId, "제목1"); + + Comment parentComment = CommentTestFixture.createComment(parentCommentId, "부모 댓글", user, notice); + + CommentDTO.Save childCommentDTO = new CommentDTO.Save(parentCommentId, "자식 댓글", List.of()); + Comment childComment = CommentTestFixture.createComment(childCommentId, childCommentDTO.content(), user, notice); + + given(commentMapper.fromCommentDto(childCommentDTO, notice, user, parentComment)).willReturn(childComment); + given(userGetService.find(user.getId())).willReturn(user); + given(commentFindService.find(parentComment.getId())).willReturn(parentComment); + given(noticeFindService.find(notice.getId())).willReturn(notice); + given(fileMapper.toFileList(childCommentDTO.files(), childComment)).willReturn(List.of()); + + // when + noticeCommentUsecase.saveNoticeComment(childCommentDTO, noticeId, userId); + + // then + verify(commentFindService).find(parentComment.getId()); + verify(commentSaveService).save(childComment); + + assertThat(parentComment.getChildren()).contains(childComment); + } + + @Test + @DisplayName("공지사항 댓글 수정 시 작성자와 수정 요청자가 다르면 예외가 발생한다") + void updateNoticeComment_throwsException_whenUserIsNotOwner() { + Long different = 2L; + Long noticeId = 1L; + Long commentId = 1L; + // given + User user = UserTestFixture.createActiveUser1(1L); + User user2 = UserTestFixture.createActiveUser1(2L); + Notice notice = NoticeTestFixture.createNotice(noticeId, "제목1"); + + CommentDTO.Update dto = new CommentDTO.Update("수정 완료", List.of()); + + Comment comment = CommentTestFixture.createComment(commentId, dto.content(), user, notice); + + given(userGetService.find(user2.getId())).willReturn(user2); + given(noticeFindService.find(notice.getId())).willReturn(notice); + given(commentFindService.find(comment.getId())).willReturn(comment); + + // when & then + assertThrows(UserNotMatchException.class, () -> + noticeCommentUsecase.updateNoticeComment(dto, noticeId, comment.getId(), different) + ); + } +} diff --git a/src/test/java/leets/weeth/domain/comment/test/fixture/CommentTestFixture.java b/src/test/java/leets/weeth/domain/comment/test/fixture/CommentTestFixture.java new file mode 100644 index 00000000..30e3e2fc --- /dev/null +++ b/src/test/java/leets/weeth/domain/comment/test/fixture/CommentTestFixture.java @@ -0,0 +1,20 @@ +package leets.weeth.domain.comment.test.fixture; + +import leets.weeth.domain.board.domain.entity.Notice; +import leets.weeth.domain.comment.domain.entity.Comment; +import leets.weeth.domain.user.domain.entity.User; + +import java.util.ArrayList; + +public class CommentTestFixture { + public static Comment createComment(Long id, String content, User user, Notice noice){ + return Comment.builder() + .id(id) + .content(content) + .notice(noice) + .user(user) + .children(new ArrayList<>()) + .isDeleted(Boolean.FALSE) + .build(); + } +} diff --git a/src/test/java/leets/weeth/domain/file/test/fixture/FileTestFixture.java b/src/test/java/leets/weeth/domain/file/test/fixture/FileTestFixture.java new file mode 100644 index 00000000..18e08c0e --- /dev/null +++ b/src/test/java/leets/weeth/domain/file/test/fixture/FileTestFixture.java @@ -0,0 +1,23 @@ +package leets.weeth.domain.file.test.fixture; + +import leets.weeth.domain.board.domain.entity.Notice; +import leets.weeth.domain.file.domain.entity.File; + +public class FileTestFixture { + public static File createFile(Long id, String fileName, String fileUrl){ + return File.builder() + .id(id) + .fileName(fileName) + .fileUrl(fileUrl) + .build(); + } + + public static File createFile(Long id, String fileName, String fileUrl, Notice notice){ + return File.builder() + .id(id) + .fileName(fileName) + .fileUrl(fileUrl) + .notice(notice) + .build(); + } +} diff --git a/src/test/java/leets/weeth/domain/user/test/fixture/UserTestFixture.java b/src/test/java/leets/weeth/domain/user/test/fixture/UserTestFixture.java index 20009210..a3668645 100644 --- a/src/test/java/leets/weeth/domain/user/test/fixture/UserTestFixture.java +++ b/src/test/java/leets/weeth/domain/user/test/fixture/UserTestFixture.java @@ -1,6 +1,7 @@ package leets.weeth.domain.user.test.fixture; import leets.weeth.domain.user.domain.entity.User; +import leets.weeth.domain.user.domain.entity.enums.Role; import leets.weeth.domain.user.domain.entity.enums.Status; public class UserTestFixture { @@ -73,4 +74,14 @@ public static User createWaitingUser2(Long id) { .build(); } + public static User createAdmin(Long id) { + return User.builder() + .id(id) + .name("적순") + .email("admin@test.com") + .status(Status.ACTIVE) + .role(Role.ADMIN) + .build(); + } + }