diff --git a/src/test/java/com/example/spot/service/memberstudy/MemberStudyCommandServiceTest.java b/src/test/java/com/example/spot/service/memberstudy/MemberStudyCommandServiceTest.java new file mode 100644 index 00000000..8e79e214 --- /dev/null +++ b/src/test/java/com/example/spot/service/memberstudy/MemberStudyCommandServiceTest.java @@ -0,0 +1,242 @@ +package com.example.spot.service.memberstudy; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.BDDMockito.*; +import static org.mockito.Mockito.when; + +import com.example.spot.api.exception.handler.StudyHandler; +import com.example.spot.domain.Member; +import com.example.spot.domain.mapping.MemberStudy; +import com.example.spot.domain.study.Study; +import com.example.spot.domain.study.ToDoList; +import com.example.spot.repository.MemberRepository; +import com.example.spot.repository.MemberStudyRepository; +import com.example.spot.repository.StudyRepository; +import com.example.spot.repository.ToDoListRepository; +import com.example.spot.web.dto.memberstudy.request.toDo.ToDoListRequestDTO.ToDoListCreateDTO; +import com.example.spot.web.dto.memberstudy.request.toDo.ToDoListResponseDTO.ToDoListCreateResponseDTO; +import com.example.spot.web.dto.memberstudy.request.toDo.ToDoListResponseDTO.ToDoListUpdateResponseDTO; +import java.time.LocalDate; +import java.util.Collections; +import java.util.Optional; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.BDDMockito; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; + +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) +public class MemberStudyCommandServiceTest { + + @InjectMocks + private MemberStudyCommandServiceImpl memberStudyCommandService; + + @Mock + private StudyRepository studyRepository; + + @Mock + private MemberStudyRepository memberStudyRepository; + + @Mock + private MemberRepository memberRepository; + + @Mock + private ToDoListRepository toDoListRepository; + + @Mock + private Study study; + + @Mock + private Member member; + + @Mock + private MemberStudy memberStudy; + + @Mock + private ToDoList toDoList; + + private ToDoListCreateDTO requestDTO; + + @BeforeEach + void init() { + requestDTO = ToDoListCreateDTO.builder() + .content("test") + .date(LocalDate.EPOCH) + .build(); + + given(toDoList.getStudy()).willReturn(study); + given(study.getId()).willReturn(1L); + given(toDoList.getMember()).willReturn(member); + given(member.getId()).willReturn(1L); + + Authentication authentication = new UsernamePasswordAuthenticationToken("1", null, Collections.emptyList()); + SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); + securityContext.setAuthentication(authentication); + SecurityContextHolder.setContext(securityContext); + } + + /* ---------------------------- To-Do 생성 관련 메서드 ---------------------------- */ + + @Test + @DisplayName("To-Do 생성 - 성공") + void createToDoList() { + // given + when(studyRepository.findById(anyLong())).thenReturn(Optional.ofNullable(study)); + when(memberStudyRepository.findByMemberIdAndStudyIdAndStatus(anyLong(), anyLong(), any())).thenReturn( + Optional.ofNullable(memberStudy)); + when(memberRepository.findById(anyLong())).thenReturn(Optional.ofNullable(member)); + + when(toDoListRepository.save(any())).thenReturn(toDoList); + + // when + ToDoListCreateResponseDTO responseDTO = memberStudyCommandService.createToDoList(1L, requestDTO); + + // then + assertEquals(responseDTO.getContent(), requestDTO.getContent()); + } + + @Test + @DisplayName("To-Do 생성 - 스터디 회원이 아닌 경우") + void ToDo_생성_시_스터디_회원이_아닌_경우() { + // given + when(studyRepository.findById(anyLong())).thenReturn(Optional.ofNullable(study)); + when(memberStudyRepository.findByMemberIdAndStudyIdAndStatus(anyLong(), anyLong(), any())).thenReturn( + Optional.empty()); + + + // when & then + assertThrows(StudyHandler.class, () -> { + memberStudyCommandService.createToDoList(1L, requestDTO); + }); + } + + /* ---------------------------- To-Do 수정 관련 메서드 ---------------------------- */ + + @Test + @DisplayName("To-Do 수정 - 성공") + void ToDo_수정_성공() { + // given + when(toDoListRepository.findById(anyLong())).thenReturn(Optional.ofNullable(toDoList)); + + // when + ToDoListUpdateResponseDTO responseDTO = memberStudyCommandService.updateToDoList(1L,1L, requestDTO); + + // then + assertEquals(false, responseDTO.isDone()); + + } + + @Test + @DisplayName("To-Do 수정 - To-Do가 없는 경우") + void ToDo_수정_시_ToDo가_없는_경우() { + // given + when(toDoListRepository.findById(anyLong())).thenReturn(Optional.empty()); + + // when & then + assertThrows(StudyHandler.class, () -> { + memberStudyCommandService.updateToDoList(1L,1L, requestDTO); + }); + } + + @Test + @DisplayName("To-Do 수정 - To-Do가 다른 스터디의 것인 경우") + void ToDo_수정_시_ToDo가_다른_스터디의_것인_경우() { + // given + when(toDoListRepository.findById(anyLong())).thenReturn(Optional.ofNullable(toDoList)); + given(toDoList.getStudy()).willReturn(Mockito.mock(Study.class)); + given(toDoList.getStudy().getId()).willReturn(2L); + + // when & then + assertThrows(StudyHandler.class, () -> { + memberStudyCommandService.updateToDoList(1L,1L, requestDTO); + }); + } + + @Test + @DisplayName("To-Do 수정 - To-Do가 다른 회원의 것인 경우") + void ToDo_수정_시_ToDo가_다른_회원의_것인_경우() { + // given + when(toDoListRepository.findById(anyLong())).thenReturn(Optional.ofNullable(toDoList)); + given(toDoList.getMember()).willReturn(Mockito.mock(Member.class)); + given(toDoList.getMember().getId()).willReturn(2L); + + // when & then + assertThrows(StudyHandler.class, () -> { + memberStudyCommandService.updateToDoList(1L,1L, requestDTO); + }); + } + + /* ---------------------------- To-Do 삭제 관련 메서드 ---------------------------- */ + + @Test + @DisplayName("To-Do 삭제 - 성공") + void ToDo_삭제_성공() { + // given + when(toDoListRepository.findById(anyLong())).thenReturn(Optional.ofNullable(toDoList)); + when(memberStudyRepository.findByMemberIdAndStudyIdAndStatus(anyLong(), anyLong(), any())).thenReturn( + Optional.ofNullable(memberStudy)); + + // when + ToDoListUpdateResponseDTO responseDTO = memberStudyCommandService.deleteToDoList(1L, 1L); + + // then + verify(toDoListRepository, times(1)).deleteById(1L); + } + + @Test + @DisplayName("To-Do 삭제 - To-Do가 없는 경우") + void ToDo_삭제_시_ToDo가_없는_경우() { + // given + when(toDoListRepository.findById(anyLong())).thenReturn(Optional.empty()); + + // when & then + assertThrows(StudyHandler.class, () -> { + memberStudyCommandService.deleteToDoList(1L, 1L); + }); + } + + @Test + @DisplayName("To-Do 삭제 - To-Do가 다른 스터디의 것인 경우") + void ToDo_삭제_시_ToDo가_다른_스터디의_것인_경우() { + // given + when(toDoListRepository.findById(anyLong())).thenReturn(Optional.ofNullable(toDoList)); + given(toDoList.getStudy()).willReturn(Mockito.mock(Study.class)); + given(toDoList.getStudy().getId()).willReturn(2L); + + // when & then + assertThrows(StudyHandler.class, () -> { + memberStudyCommandService.deleteToDoList(1L, 1L); + }); + } + + @Test + @DisplayName("To-Do 삭제 - To-Do가 다른 회원의 것인 경우") + void ToDo_삭제_시_ToDo가_다른_회원의_것인_경우() { + // given + when(toDoListRepository.findById(anyLong())).thenReturn(Optional.ofNullable(toDoList)); + given(toDoList.getMember()).willReturn(Mockito.mock(Member.class)); + given(toDoList.getMember().getId()).willReturn(2L); + + // when & then + assertThrows(StudyHandler.class, () -> { + memberStudyCommandService.deleteToDoList(1L, 1L); + }); + } + + + +} diff --git a/src/test/java/com/example/spot/service/memberstudy/MemberStudyQueryServiceTest.java b/src/test/java/com/example/spot/service/memberstudy/MemberStudyQueryServiceTest.java index 94e5b029..01c7db33 100644 --- a/src/test/java/com/example/spot/service/memberstudy/MemberStudyQueryServiceTest.java +++ b/src/test/java/com/example/spot/service/memberstudy/MemberStudyQueryServiceTest.java @@ -8,16 +8,20 @@ import com.example.spot.domain.study.Schedule; import com.example.spot.domain.study.Study; import com.example.spot.domain.study.StudyPost; +import com.example.spot.domain.study.ToDoList; import com.example.spot.repository.MemberRepository; import com.example.spot.repository.MemberStudyRepository; import com.example.spot.repository.ScheduleRepository; import com.example.spot.repository.StudyPostRepository; +import com.example.spot.repository.ToDoListRepository; import com.example.spot.security.utils.SecurityUtils; +import com.example.spot.web.dto.memberstudy.request.toDo.ToDoListResponseDTO.ToDoListSearchResponseDTO; import com.example.spot.web.dto.study.response.StudyMemberResponseDTO; import com.example.spot.web.dto.study.response.StudyMemberResponseDTO.StudyApplicantDTO; import com.example.spot.web.dto.study.response.StudyMemberResponseDTO.StudyApplyMemberDTO; import com.example.spot.web.dto.study.response.StudyPostResponseDTO; import com.example.spot.web.dto.study.response.StudyScheduleResponseDTO; +import java.time.LocalDate; import java.util.Collections; import java.util.List; import java.util.Map; @@ -39,6 +43,7 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoSettings; import org.mockito.quality.Strictness; +import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; @@ -61,25 +66,40 @@ public class MemberStudyQueryServiceTest { @Mock private ScheduleRepository scheduleRepository; @Mock + private ToDoListRepository toDoListRepository; + @Mock private SecurityUtils securityUtils; private static Member member; + private static Member member2; private static Study study; private static MemberStudy memberStudy; + private static MemberStudy studyMember; private static MemberStudy apply; + private static ToDoList toDoList; @BeforeEach void setup(){ member = Member.builder() .id(1L) .build(); + member2 = Member.builder() + .id(2L) + .build(); + study = Study.builder() .build(); memberStudy = MemberStudy.builder() .introduction("title").study(study).member(member).isOwned(true).status(ApplicationStatus.APPROVED).build(); + apply = MemberStudy.builder() .introduction("title").study(study).member(member).isOwned(false).status(ApplicationStatus.APPLIED).build(); + studyMember = MemberStudy.builder() + .introduction("title").study(study).member(member2).isOwned(true).status(ApplicationStatus.APPROVED).build(); + toDoList = ToDoList.builder() + .id(1L) + .build(); Long studyId = 1L; @@ -361,4 +381,110 @@ void setup(){ // when & then assertThrows(GeneralException.class, () -> memberStudyQueryService.isApplied(100L)); } + + /* ------------------------------------------------ To-Do 조회 --------------------------------------------------- */ + + @Test + @DisplayName("To-Do 조회 - 성공") + void ToDo_조회_성공() { + // given + when(memberStudyRepository.findByMemberIdAndStudyIdAndStatus(1L, 100L, ApplicationStatus.APPROVED)) + .thenReturn(Optional.ofNullable(memberStudy)); + when(toDoListRepository.findByStudyIdAndMemberIdAndDateOrderByCreatedAtDesc(anyLong(), anyLong(), any(), any())) + .thenReturn(List.of(toDoList)); + when(toDoListRepository.countByStudyIdAndMemberIdAndDate(anyLong(), anyLong(), any())) + .thenReturn(1L); + + // when + ToDoListSearchResponseDTO responseDTO = memberStudyQueryService.getToDoList(1L, LocalDate.MAX, PageRequest.of(0, 10)); + + // then + assertEquals(1, responseDTO.getTotalElements()); + assertEquals(1L, responseDTO.getContent().get(0).getId()); + } + + @Test + @DisplayName("To-Do 조회 - 로그인 한 회원이 스터디 회원이 아닌 경우") + void ToDo_조회_시_로그인_한_회원이_스터디_회원이_아닌_경우() { + // given + when(memberStudyRepository.findByMemberIdAndStudyIdAndStatus(1L, 100L, ApplicationStatus.APPROVED)) + .thenReturn(Optional.empty()); + + // when & then + assertThrows(GeneralException.class, () -> memberStudyQueryService.getToDoList(100L, LocalDate.MAX, PageRequest.of(0, 10))); + } + + @Test + @DisplayName("To-Do 조회 - 회원의 To-Do가 존재하지 않는 경우") + void ToDo가_존재하지_않는_경우() { + // given + when(memberStudyRepository.findByMemberIdAndStudyIdAndStatus(1L, 100L, ApplicationStatus.APPROVED)) + .thenReturn(Optional.ofNullable(memberStudy)); + when(toDoListRepository.findByStudyIdAndMemberIdAndDateOrderByCreatedAtDesc(anyLong(), anyLong(), any(), any())) + .thenReturn(List.of()); + + // when & then + assertThrows(GeneralException.class, () -> memberStudyQueryService.getToDoList(100L, LocalDate.MAX, PageRequest.of(0, 10))); + } + + /* ------------------------------------------------ 다른 스터디원의 To-Do 조회 --------------------------------------------------- */ + + @Test + @DisplayName("특정 스터디 원 To-Do 조회 - 성공") + void 스터디_원_ToDo_조회_성공() { + // given + when(memberStudyRepository.findByMemberIdAndStudyIdAndStatus(1L, 1L, ApplicationStatus.APPROVED)) + .thenReturn(Optional.ofNullable(memberStudy)); + when(memberStudyRepository.findByMemberIdAndStudyIdAndStatus(2L, 1L, ApplicationStatus.APPROVED)) + .thenReturn(Optional.ofNullable(studyMember)); + when(toDoListRepository.findByStudyIdAndMemberIdAndDateOrderByCreatedAtDesc(anyLong(), anyLong(), any(), any())) + .thenReturn(List.of(toDoList)); + when(toDoListRepository.countByStudyIdAndMemberIdAndDate(anyLong(), anyLong(), any())) + .thenReturn(1L); + + // when + ToDoListSearchResponseDTO responseDTO = memberStudyQueryService.getMemberToDoList(1L, 2L, LocalDate.MAX, PageRequest.of(0, 10)); + + // then + assertEquals(1, responseDTO.getTotalElements()); + assertEquals(1L, responseDTO.getContent().get(0).getId()); + } + + @Test + @DisplayName("특정 스터디 원 To-Do 조회 - 로그인 한 회원이 스터디 회원이 아닌 경우") + void 스터디_원_ToDo_조회_시_로그인_한_회원이_스터디_회원이_아닌_경우() { + // given + when(memberStudyRepository.findByMemberIdAndStudyIdAndStatus(1L, 100L, ApplicationStatus.APPROVED)) + .thenReturn(Optional.empty()); + + // when & then + assertThrows(GeneralException.class, () -> memberStudyQueryService.getMemberToDoList(100L, 2L, LocalDate.MAX, PageRequest.of(0, 10))); + } + + @Test + @DisplayName("특정 스터디 원 To-Do 조회 - 조회 하려는 회원이 스터디 회원이 아닌 경우") + void 스터디_원_ToDo_조회_시_조회_하려는_회원이_스터디_회원이_아닌_경우() { + // given + when(memberStudyRepository.findByMemberIdAndStudyIdAndStatus(1L, 100L, ApplicationStatus.APPROVED)) + .thenReturn(Optional.ofNullable(memberStudy)); + when(memberStudyRepository.findByMemberIdAndStudyIdAndStatus(2L, 100L, ApplicationStatus.APPROVED)) + .thenReturn(Optional.empty()); + + // when & then + assertThrows(GeneralException.class, () -> memberStudyQueryService.getMemberToDoList(100L, 2L, LocalDate.MAX, PageRequest.of(0, 10))); + } + + @Test + @DisplayName("특정 스터디 원 To-Do 조회 - 회원의 To-Do가 존재하지 않는 경우") + void 스터디_원_ToDo가_존재하지_않는_경우() { + // given + when(memberStudyRepository.findByMemberIdAndStudyIdAndStatus(1L, 100L, ApplicationStatus.APPROVED)) + .thenReturn(Optional.ofNullable(memberStudy)); + when(toDoListRepository.findByStudyIdAndMemberIdAndDateOrderByCreatedAtDesc(anyLong(), anyLong(), any(), any())) + .thenReturn(List.of()); + + // when & then + assertThrows(GeneralException.class, () -> memberStudyQueryService.getToDoList(100L, LocalDate.MAX, PageRequest.of(0, 10))); + } + } diff --git a/src/test/java/com/example/spot/service/notification/NotificationCommandServiceTest.java b/src/test/java/com/example/spot/service/notification/NotificationCommandServiceTest.java new file mode 100644 index 00000000..463e9464 --- /dev/null +++ b/src/test/java/com/example/spot/service/notification/NotificationCommandServiceTest.java @@ -0,0 +1,189 @@ +package com.example.spot.service.notification; + + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.BDDMockito.*; +import static org.mockito.Mockito.when; + +import com.example.spot.api.exception.GeneralException; +import com.example.spot.domain.Member; +import com.example.spot.domain.Notification; +import com.example.spot.domain.enums.ApplicationStatus; +import com.example.spot.domain.enums.NotifyType; +import com.example.spot.domain.mapping.MemberStudy; +import com.example.spot.domain.study.Study; +import com.example.spot.repository.MemberStudyRepository; +import com.example.spot.repository.NotificationRepository; +import com.example.spot.web.dto.notification.NotificationResponseDTO.NotificationProcessDTO; +import java.time.LocalDateTime; +import java.util.Optional; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.BDDMockito; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; +import org.springframework.data.domain.Pageable; + +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) +public class NotificationCommandServiceTest { + + @InjectMocks + private NotificationCommandServiceImpl notificationCommandService; + + @Mock + private NotificationRepository notificationRepository; + + @Mock + private MemberStudyRepository memberStudyRepository; + + @Mock + private Member member; + + @Mock + private Study study; + + private Notification notification1; + private Notification notification2; + private Notification notification3; + + private MemberStudy memberStudy; + + @BeforeEach + void init() { + this.notification1 = Notification.builder() + .id(1L).study(study).member(member).type(NotifyType.STUDY_APPLY).notifierName("Test") + .isChecked(false).build(); + this.notification2 = Notification.builder() + .id(2L).study(study).member(member).type(NotifyType.ANNOUNCEMENT).notifierName("Test") + .isChecked(false).build(); + this.notification2 = Notification.builder() + .id(3L).study(study).member(member).type(NotifyType.STUDY_APPLY).notifierName("Test") + .isChecked(true).build(); + + this.memberStudy = MemberStudy.builder().status(ApplicationStatus.APPLIED).build(); + } + + /* --------------------------------- 알림 읽음 처리 ----------------------------------- */ + + @Test + @DisplayName("알림 읽음 처리 성공") + void 알림_읽음_처리_성공() { + // given + given(member.getId()).willReturn(1L); + + when(notificationRepository.findById(anyLong())) + .thenReturn(Optional.ofNullable(notification1)); + + // when + NotificationProcessDTO response = notificationCommandService.readNotification(1L, 1L); + + // then + assertEquals(true, response.isAccept()); + } + + @Test + @DisplayName("알림이 없는 경우") + void 알림이_없는_경우() { + // given + when(notificationRepository.findById(anyLong())) + .thenReturn(Optional.empty()); + + // when & then + assertThrows(GeneralException.class, () -> { + notificationCommandService.readNotification(1L, 1L); + }); + } + + @Test + @DisplayName("알림이 사용자에게 속하지 않는 경우") + void 알림이_사용자에게_속하지_않는_경우() { + // given + given(member.getId()).willReturn(1L); + + when(notificationRepository.findById(anyLong())) + .thenReturn(Optional.ofNullable(notification1)); + + // when & then + assertThrows(GeneralException.class, () -> { + notificationCommandService.readNotification(2L, 1L); + }); + } + + @Test + @DisplayName("이미 읽음 처리된 경우") + void 이미_읽음_처리_된_경우() { + // given + given(member.getId()).willReturn(1L); + + when(notificationRepository.findById(anyLong())) + .thenReturn(Optional.ofNullable(notification3)); + + // when & then + assertThrows(GeneralException.class, () -> { + notificationCommandService.readNotification(1L, 1L); + }); + } + + /* --------------------------------- 스터디 알림 처리 ----------------------------------- */ + + @Test + @DisplayName("스터디 신청 처리 성공") + void 스터디_신청_처리_성공() { + // given + when(notificationRepository.findByMemberIdAndStudyIdAndTypeAndIsChecked( + anyLong(), anyLong(), any(), anyBoolean() + )).thenReturn(Optional.ofNullable(notification1)); + + when(memberStudyRepository.findByMemberIdAndStudyIdAndStatus( + anyLong(), anyLong(), any() + )).thenReturn(Optional.ofNullable(memberStudy)); + + // when + NotificationProcessDTO response = + notificationCommandService.joinAppliedStudy(1L, 1L, true); + + // then + assertEquals(true, response.isAccept()); + } + + @Test + @DisplayName("스터디 신청 알림이 이미 처리 된 경우") + void 스터디_알림이_이미_읽음_처리_된_경우() { + // given + when(notificationRepository.findByMemberIdAndStudyIdAndTypeAndIsChecked( + anyLong(), anyLong(), any(), anyBoolean() + )).thenReturn(Optional.ofNullable(notification3)); + + // when & then + assertThrows(GeneralException.class, () -> { + notificationCommandService.joinAppliedStudy(1L, 1L, true); + }); + } + + @Test + @DisplayName("스터디 신청 알림이 없는 경우") + void 스터디_신청이_없는_경우() { + // given + when(notificationRepository.findByMemberIdAndStudyIdAndTypeAndIsChecked( + anyLong(), anyLong(), any(), anyBoolean() + )).thenReturn(Optional.ofNullable(notification1)); + + when(memberStudyRepository.findByMemberIdAndStudyIdAndStatus( + anyLong(), anyLong(), any() + )).thenReturn(Optional.empty()); + + // when & then + assertThrows(GeneralException.class, () -> { + notificationCommandService.joinAppliedStudy(1L, 1L, true); + }); + } +} diff --git a/src/test/java/com/example/spot/service/notification/NotificationQueryServiceTest.java b/src/test/java/com/example/spot/service/notification/NotificationQueryServiceTest.java new file mode 100644 index 00000000..1d2004ee --- /dev/null +++ b/src/test/java/com/example/spot/service/notification/NotificationQueryServiceTest.java @@ -0,0 +1,147 @@ +package com.example.spot.service.notification; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.when; + +import com.example.spot.api.exception.GeneralException; +import com.example.spot.domain.Member; +import com.example.spot.domain.Notification; +import com.example.spot.domain.enums.NotifyType; +import com.example.spot.domain.study.Study; +import com.example.spot.repository.NotificationRepository; +import com.example.spot.web.dto.notification.NotificationResponseDTO.NotificationListDTO; +import com.example.spot.web.dto.notification.NotificationResponseDTO.StduyNotificationListDTO; +import com.example.spot.web.dto.notification.NotificationResponseDTO.StduyNotificationListDTO.StudyNotificationDTO; +import java.util.List; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.BDDMockito; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; +import org.springframework.data.domain.Pageable; + +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) +class NotificationQueryServiceTest { + + @InjectMocks + private NotificationQueryServiceImpl notificationQueryService; + + @Mock + private NotificationRepository notificationRepository; + + @Mock + private Member member; + + @Mock + private Study study; + + @Mock + private Pageable pageable; + + private Notification notification1; + private Notification notification2; + private Notification notification3; + + @BeforeEach + void init() { + this.notification1 = Notification.builder() + .id(1L).study(study).member(member).type(NotifyType.STUDY_APPLY).notifierName("Test") + .isChecked(false).build(); + this.notification2 = Notification.builder() + .id(2L).study(study).member(member).type(NotifyType.ANNOUNCEMENT).notifierName("Test") + .isChecked(false).build(); + this.notification2 = Notification.builder() + .id(3L).study(study).member(member).type(NotifyType.STUDY_APPLY).notifierName("Test") + .isChecked(true).build(); + } + + + /*---------------------- 스터디 알림 조회 ---------------------- */ + + @Test + @DisplayName("스터디 알림 조회 성공") + void 스터디_알림_조회_성공() { + // given + given(notification1.getStudy().getId()).willReturn(1L); + given(notification1.getStudy().getTitle()).willReturn("스터디 참여"); + given(notification1.getStudy().getProfileImage()).willReturn("img"); + + when(notificationRepository.findByMemberIdAndTypeAndIsChecked( + anyLong(), any(), any(), anyBoolean() + )).thenReturn(List.of(notification1)); + + + // when + StduyNotificationListDTO response = notificationQueryService.getAllAppliedStudyNotification(1L, pageable); + + // then + assertEquals(1L, response.getTotalNotificationCount()); + assertEquals(1L, response.getNotifications().get(0).getNotificationId()); + } + + @Test + @DisplayName("참여 신청한 스터디 알림이 없는 경우") + void 스터디_알림이_없는_경우() { + // given + when(notificationRepository.findByMemberIdAndTypeAndIsChecked( + anyLong(), any(), any(), anyBoolean() + )).thenReturn(List.of()); + + // when & then + assertThrows(GeneralException.class, () -> { + notificationQueryService.getAllAppliedStudyNotification( + 1L, pageable); + }); + } + + /*---------------------- 알림 전체 조회 ---------------------- */ + + @Test + @DisplayName("전체 알림 조회 성공") + void 전체_알림_조회_성공() { + // given + given(notification1.getStudy().getTitle()).willReturn("스터디 참여"); + + when(notificationRepository.findByMemberIdAndTypeNot( + anyLong(), any(), any() + )).thenReturn(List.of(notification1, notification2)); + + + // when + NotificationListDTO response = notificationQueryService.getAllNotifications(1L, pageable); + + // then + assertEquals(2L, response.getTotalNotificationCount()); + assertEquals(1L, response.getNotifications().get(0).getNotificationId()); + } + + @Test + @DisplayName("조회할 알림이 없는 경우") + void 조회할_알림이_없는_경우() { + // given + + when(notificationRepository.findByMemberIdAndTypeNot( + anyLong(), any(), any() + )).thenReturn(List.of()); + + // when & then + assertThrows(GeneralException.class, () -> { + notificationQueryService.getAllNotifications( + 1L, pageable); + }); + } + +}