From 6f655a63e82745dc249341c9f837d973ae75c752 Mon Sep 17 00:00:00 2001 From: its-sky Date: Mon, 1 Apr 2024 16:44:37 +0900 Subject: [PATCH 1/4] =?UTF-8?q?[Chore]=20#259=20-=20Test=20Part=20?= =?UTF-8?q?=EC=BB=A8=EB=B2=A4=EC=85=98=20=EB=A7=9E=EC=B6=94=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/moonshot/objective/service/ObjectiveServiceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moonshot-api/src/test/java/org/moonshot/objective/service/ObjectiveServiceTest.java b/moonshot-api/src/test/java/org/moonshot/objective/service/ObjectiveServiceTest.java index 52a40ca5..b931a496 100644 --- a/moonshot-api/src/test/java/org/moonshot/objective/service/ObjectiveServiceTest.java +++ b/moonshot-api/src/test/java/org/moonshot/objective/service/ObjectiveServiceTest.java @@ -160,7 +160,7 @@ static void setUp() { @Test @DisplayName("Objective의 히스토리를 조회합니다") void Objective의_히스토리를_조회합니다() { - //given + // given Objective objective1 = Objective.builder() .user(fakeUser) .title("Objective 1") From 4de5d804b39284876c3a02d38720e7f486bd570c Mon Sep 17 00:00:00 2001 From: its-sky Date: Mon, 1 Apr 2024 22:37:35 +0900 Subject: [PATCH 2/4] =?UTF-8?q?[Feat]=20#259=20-=20KeyResultService=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/KeyResultServiceTest.java | 324 ++++++++++++++++++ 1 file changed, 324 insertions(+) create mode 100644 moonshot-api/src/test/java/org/moonshot/keyresult/service/KeyResultServiceTest.java diff --git a/moonshot-api/src/test/java/org/moonshot/keyresult/service/KeyResultServiceTest.java b/moonshot-api/src/test/java/org/moonshot/keyresult/service/KeyResultServiceTest.java new file mode 100644 index 00000000..cebb1730 --- /dev/null +++ b/moonshot-api/src/test/java/org/moonshot/keyresult/service/KeyResultServiceTest.java @@ -0,0 +1,324 @@ +package org.moonshot.keyresult.service; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import java.time.LocalDate; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.BeforeAll; +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.moonshot.common.model.Period; +import org.moonshot.exception.BadRequestException; +import org.moonshot.keyresult.dto.request.KeyResultCreateRequestDto; +import org.moonshot.keyresult.dto.request.KeyResultCreateRequestInfoDto; +import org.moonshot.keyresult.dto.request.KeyResultModifyRequestDto; +import org.moonshot.keyresult.dto.response.KRDetailResponseDto; +import org.moonshot.keyresult.model.KRState; +import org.moonshot.keyresult.model.KeyResult; +import org.moonshot.keyresult.repository.KeyResultRepository; +import org.moonshot.log.dto.response.AchieveResponseDto; +import org.moonshot.log.model.Log; +import org.moonshot.log.model.LogState; +import org.moonshot.log.repository.LogRepository; +import org.moonshot.log.service.LogService; +import org.moonshot.objective.model.Category; +import org.moonshot.objective.model.Objective; +import org.moonshot.objective.repository.ObjectiveRepository; +import org.moonshot.task.dto.request.TaskCreateRequestDto; +import org.moonshot.task.repository.TaskRepository; +import org.moonshot.task.service.TaskService; +import org.moonshot.user.model.User; + +@ExtendWith(MockitoExtension.class) +class KeyResultServiceTest { + + @Mock + private ObjectiveRepository objectiveRepository; + @Mock + private KeyResultRepository keyResultRepository; + @Mock + private TaskRepository taskRepository; + @Mock + private TaskService taskService; + @Mock + private LogService logService; + @Mock + private LogRepository logRepository; + @InjectMocks + private KeyResultService keyResultService; + + private static User fakeUser; + + @BeforeAll + static void setUp() { + Long fakeUserId = 1L; + String fakeUserNickname = "tester"; + fakeUser = User.buildWithId().id(fakeUserId).nickname(fakeUserNickname).build(); + } + + @Test + @DisplayName("Objective와 함께 생성하는 KeyResult를 생성합니다") + void Objective와_함께_생성하는_KeyResult를_생성합니다() { + //given + Objective testObjective = Objective.builder() + .title("testObjective") + .category(Category.ECONOMY) + .content("testObjective Content") + .period(Period.of(LocalDate.now(), LocalDate.from(LocalDate.now().plusDays(30)))) + .user(fakeUser) + .build(); + KeyResult testKeyResult = mock(KeyResult.class); + TaskCreateRequestDto firstTaskDto = new TaskCreateRequestDto("test Task 0", 0); + TaskCreateRequestDto secondTaskDto = new TaskCreateRequestDto("test Task 1", 1); + TaskCreateRequestDto thirdTaskDto = new TaskCreateRequestDto("test Task 2", 2); + List taskList = List.of(firstTaskDto, secondTaskDto, thirdTaskDto); + KeyResultCreateRequestInfoDto firstKeyResultDto = new KeyResultCreateRequestInfoDto( + "test KR", LocalDate.now(), LocalDate.from(LocalDate.now().plusDays(30)), + 0, 500000L, "건", taskList + ); + KeyResultCreateRequestInfoDto secondKeyResultDto = new KeyResultCreateRequestInfoDto( + "test KR", LocalDate.now(), LocalDate.from(LocalDate.now().plusDays(30)), + 1, 500000L, "건", taskList + ); + List testRequests = new java.util.ArrayList<>( + List.of(firstKeyResultDto, secondKeyResultDto)); + testRequests.add(null); + given(keyResultRepository.save(any(KeyResult.class))).willReturn(testKeyResult); + given(testKeyResult.getId()).willReturn(1L); + + //when + keyResultService.createInitKRWithObjective(testObjective, testRequests); + + //then + verify(keyResultRepository, times(2)).save(any(KeyResult.class)); + verify(logService, times(2)).createKRLog(any(KeyResultCreateRequestInfoDto.class), any(Long.class)); + verify(taskService, times(6)).saveTask(any(KeyResult.class), any(TaskCreateRequestDto.class)); + } + + @Test + @DisplayName("단일 KeyResult를 생성합니다") + void 단일_KeyResult를_생성합니다() { + // given + Objective testObjective = mock(Objective.class); + User testUser = mock(User.class); + KeyResult testKeyResult = mock(KeyResult.class); + KeyResultCreateRequestDto request = new KeyResultCreateRequestDto( + 1L, "test KR", LocalDate.now(), + LocalDate.from(LocalDate.now().plusDays(30)), + 0, 500000L, "건"); + + given(objectiveRepository.findObjectiveAndUserById(1L)).willReturn(Optional.of(testObjective)); + given(keyResultRepository.findAllByObjective(testObjective)).willReturn(List.of(testKeyResult)); + given(testObjective.getId()).willReturn(1L); + given(testObjective.getUser()).willReturn(testUser); + given(testUser.getId()).willReturn(1L); + given(keyResultRepository.save(any(KeyResult.class))).willReturn(testKeyResult); + given(testKeyResult.getId()).willReturn(2L); + + // when + keyResultService.createKeyResult(request, fakeUser.getId()); + + // then + verify(keyResultRepository, times(1)).bulkUpdateIdxIncrease(any(Integer.class), any(Integer.class), eq(1L), eq(-1L)); + verify(logService, times(1)).createKRLog(request, 2L); + } + + @Test + @DisplayName("KeyResult 생성 시 최대 보유 갯수를 넘어 예외가 발생합니다") + void KeyResult_생성_시_최대_보유_갯수를_넘어_예외가_발생합니다() { + // given + Objective testObjective = mock(Objective.class); + User testUser = mock(User.class); + List krList = mock(List.class); + KeyResultCreateRequestDto request = new KeyResultCreateRequestDto( + 1L, "test KR", LocalDate.now(), + LocalDate.from(LocalDate.now().plusDays(30)), + 0, 500000L, "건"); + + given(objectiveRepository.findObjectiveAndUserById(1L)).willReturn(Optional.of(testObjective)); + given(keyResultRepository.findAllByObjective(testObjective)).willReturn(krList); + given(krList.size()).willReturn(3); + given(testObjective.getUser()).willReturn(testUser); + given(testUser.getId()).willReturn(1L); + + // when, then + assertThatThrownBy(() -> keyResultService.createKeyResult(request, fakeUser.getId())) + .isInstanceOf(BadRequestException.class); + assertThatThrownBy(() -> keyResultService.createKeyResult(request, fakeUser.getId())) + .isInstanceOf(BadRequestException.class) + .hasMessage("허용된 Key Result 개수를 초과하였습니다"); + } + + @Test + @DisplayName("KeyResult 생성 시 인덱스가 0 ~ ListSize(최대 개수의 범위)를 벗어나 요청된 경우 예외가 발생합니다") + void KeyResult_생성_시_인덱스가_0_ListSize를_벗어나_요청된_경우_예외가_발생합니다() { + // given + Objective testObjective = mock(Objective.class); + User testUser = mock(User.class); + List krList = mock(List.class); + KeyResultCreateRequestDto request = new KeyResultCreateRequestDto( + 1L, "test KR", LocalDate.now(), + LocalDate.from(LocalDate.now().plusDays(30)), + 2, 500000L, "건"); + + given(objectiveRepository.findObjectiveAndUserById(1L)).willReturn(Optional.of(testObjective)); + given(keyResultRepository.findAllByObjective(testObjective)).willReturn(krList); + given(krList.size()).willReturn(1); + given(testObjective.getUser()).willReturn(testUser); + given(testUser.getId()).willReturn(1L); + + // when, then + assertThatThrownBy(() -> keyResultService.createKeyResult(request, fakeUser.getId())) + .isInstanceOf(BadRequestException.class); + assertThatThrownBy(() -> keyResultService.createKeyResult(request, fakeUser.getId())) + .isInstanceOf(BadRequestException.class) + .hasMessage("정상적이지 않은 KeyResult 위치입니다."); + } + + @Test + @DisplayName("KeyResult의 데이터를 조회합니다") + void KeyResult의_데이터를_조회합니다() { + // given + Long testKeyResultId = 99L; + Objective testObjective = Objective.builder() + .title("testObjective") + .user(fakeUser).build(); + KeyResult testKeyResult = KeyResult.builder() + .title("testKeyResult") + .objective(testObjective) + .target(1L) + .metric("건") + .idx(0) + .state(KRState.PROGRESS) + .period(Period.of(LocalDate.now(), LocalDate.from(LocalDate.now().plusDays(30)))) + .build(); + Log testLog = Log.builder().keyResult(testKeyResult).state(LogState.RECORD).currNum(10000L).build(); + List logList = List.of(testLog); + given(keyResultRepository.findKeyResultAndObjective(testKeyResultId)).willReturn(Optional.of(testKeyResult)); + given(logService.getLogList(testKeyResult)).willReturn(logList); + given(logService.calculateKRProgressBar(testLog, testKeyResult.getTarget())).willReturn((short) 100); + + // when + KRDetailResponseDto krDetails = keyResultService.getKRDetails(fakeUser.getId(), testKeyResultId); + + // then + assertThat(krDetails.target()).isEqualTo(1L); + assertThat(krDetails.metric()).isEqualTo("건"); + assertThat(krDetails.progressBar()).isEqualTo((short) 100); + assertThat(krDetails.krState()).isEqualTo(KRState.PROGRESS.getValue()); + assertThat(krDetails.title()).isEqualTo("testKeyResult : "); + } + + @Test + @DisplayName("KeyResult의 제목 및 날짜 데이터를 수정합니다") + void KeyResult의_제목_및_날짜_데이터를_수정합니다() { + // given + Long testKeyResultId = 99L; + KeyResult testKeyResult = mock(KeyResult.class); + Objective testObjective = mock(Objective.class); + KeyResultModifyRequestDto request = new KeyResultModifyRequestDto( + testKeyResultId, "modified KeyResult Title", LocalDate.of(2024, 4, 1), + LocalDate.of(2024, 5, 1), null, null, null); + given(keyResultRepository.findKeyResultAndObjective(testKeyResultId)).willReturn(Optional.of(testKeyResult)); + given(testKeyResult.getObjective()).willReturn(testObjective); + given(testKeyResult.getPeriod()).willReturn(Period.of(LocalDate.of(2023, 4, 1), LocalDate.of(2023, 5, 1))); + given(testObjective.getPeriod()).willReturn(Period.of(LocalDate.of(2023, 4, 1), LocalDate.of(2025, 5, 1))); + given(testObjective.getUser()).willReturn(fakeUser); + + // when + keyResultService.modifyKeyResult(request, fakeUser.getId()); + + // then + verify(testKeyResult, times(1)).modifyTitle(request.krTitle()); + verify(testKeyResult, times(1)).modifyPeriod(any(Period.class)); + } + + @Test + @DisplayName("KeyResult의 상태 데이터를 수정합니다") + void KeyResult의_상태_데이터를_수정합니다() { + // given + Long testKeyResultId = 99L; + KeyResult testKeyResult = mock(KeyResult.class); + Objective testObjective = mock(Objective.class); + KeyResultModifyRequestDto request = new KeyResultModifyRequestDto( + testKeyResultId, null, null, null, null, KRState.DONE, null); + given(keyResultRepository.findKeyResultAndObjective(testKeyResultId)).willReturn(Optional.of(testKeyResult)); + given(testKeyResult.getObjective()).willReturn(testObjective); + given(testObjective.getUser()).willReturn(fakeUser); + + // when + Optional response = keyResultService.modifyKeyResult(request, fakeUser.getId()); + + // then + verify(testKeyResult, times(1)).modifyState(KRState.DONE); + assertThat(response.isEmpty()).isEqualTo(true); + } + + @Test + @DisplayName("KeyResult 수정 시 목표치와 체크인 내용이 둘다 없을 경우 예외가 발생합니다") + void KeyResult_수정_시_목표치와_체크인_내용이_둘다_없을_경우_예외가_발생합니다() { + // given + Long testKeyResultId = 99L; + KeyResult testKeyResult = mock(KeyResult.class); + Objective testObjective = mock(Objective.class); + KeyResultModifyRequestDto request = new KeyResultModifyRequestDto( + testKeyResultId, null, null, null, null, null, null); + given(keyResultRepository.findKeyResultAndObjective(testKeyResultId)).willReturn(Optional.of(testKeyResult)); + given(testKeyResult.getObjective()).willReturn(testObjective); + given(testObjective.getUser()).willReturn(fakeUser); + + // when, then + assertThatThrownBy(() -> keyResultService.modifyKeyResult(request, fakeUser.getId())) + .isInstanceOf(BadRequestException.class); + assertThatThrownBy(() -> keyResultService.modifyKeyResult(request, fakeUser.getId())) + .isInstanceOf(BadRequestException.class) + .hasMessage("KR 수정시 목표값과 체크인 로그는 필수 입력값입니다."); + } + + @Test + @DisplayName("KeyResult의 목표치를 수정하고 체크인 로그를 추가합니다") + void KeyResult의_목표치를_수정하고_체크인_로그를_추가합니다() { + // given + Long testKeyResultId = 99L; + KeyResult testKeyResult = mock(KeyResult.class); + Objective testObjective = mock(Objective.class); + Log testLog = mock(Log.class); + Log prevTestLog = mock(Log.class); + KeyResultModifyRequestDto request = new KeyResultModifyRequestDto( + testKeyResultId, null, null, null, 100000L, null, "new check-in"); + given(keyResultRepository.findKeyResultAndObjective(testKeyResultId)).willReturn(Optional.of(testKeyResult)); + given(testKeyResult.getObjective()).willReturn(testObjective); + given(testKeyResult.getTarget()).willReturn(1L); + doNothing().when(testKeyResult).modifyTarget(request.krTarget()); + + given(testObjective.getUser()).willReturn(fakeUser); + given(testLog.getKeyResult()).willReturn(testKeyResult); + given(logService.createUpdateLog(request, testKeyResult)).willReturn(testLog); + given(logRepository.findLatestLogByKeyResultId(LogState.RECORD, testKeyResultId)).willReturn(Optional.of(prevTestLog)); + + /* isKeyResultAchieved */ + given(testObjective.getProgress()).willReturn((short) 1); + + // when + Optional response = keyResultService.modifyKeyResult(request, fakeUser.getId()); + + // then + verify(testKeyResult, times(1)).modifyProgress(any(Short.class)); + verify(testObjective, times(1)).modifyProgress(any(Short.class)); + assertThat(response.isEmpty()).isEqualTo(true); + } + +} \ No newline at end of file From c25eb910a793aaad08bcfde1e8ebe7270d3e8536 Mon Sep 17 00:00:00 2001 From: its-sky Date: Mon, 1 Apr 2024 22:38:47 +0900 Subject: [PATCH 3/4] =?UTF-8?q?[Fix]=20#259=20-=20=EC=9D=98=EB=AF=B8=20?= =?UTF-8?q?=EC=97=86=EB=8A=94=20=EC=BD=94=EB=93=9C=20=ED=9D=90=EB=A6=84=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 --- .../java/org/moonshot/keyresult/service/KeyResultService.java | 2 +- .../src/main/java/org/moonshot/log/service/LogService.java | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/moonshot-api/src/main/java/org/moonshot/keyresult/service/KeyResultService.java b/moonshot-api/src/main/java/org/moonshot/keyresult/service/KeyResultService.java index bf3550d8..465f18b0 100644 --- a/moonshot-api/src/main/java/org/moonshot/keyresult/service/KeyResultService.java +++ b/moonshot-api/src/main/java/org/moonshot/keyresult/service/KeyResultService.java @@ -162,7 +162,7 @@ public Optional modifyKeyResult(final KeyResultModifyRequest throw new BadRequestException(REQUIRED_KEY_RESULT_VALUE); } - Log updateLog = logService.createUpdateLog(request, keyResult.getId()); + Log updateLog = logService.createUpdateLog(request, keyResult); validateLogNum(request.krTarget(), updateLog.getKeyResult().getTarget()); Optional prevLog = logRepository.findLatestLogByKeyResultId(LogState.RECORD, request.keyResultId()); diff --git a/moonshot-api/src/main/java/org/moonshot/log/service/LogService.java b/moonshot-api/src/main/java/org/moonshot/log/service/LogService.java index a2a4ce14..675502f4 100644 --- a/moonshot-api/src/main/java/org/moonshot/log/service/LogService.java +++ b/moonshot-api/src/main/java/org/moonshot/log/service/LogService.java @@ -62,9 +62,7 @@ public Optional createRecordLog(final Long userId, final Log return Optional.empty(); } - public Log createUpdateLog(final KeyResultModifyRequestDto request, final Long keyResultId) { - KeyResult keyResult = keyResultRepository.findById(keyResultId) - .orElseThrow(() -> new NotFoundException(NOT_FOUND_KEY_RESULT)); + public Log createUpdateLog(final KeyResultModifyRequestDto request, final KeyResult keyResult) { return logRepository.save(Log.builder() .date(LocalDateTime.now()) .state(LogState.UPDATE) From 3fd1492f04cf646b597c3f65298135940a02cb93 Mon Sep 17 00:00:00 2001 From: its-sky Date: Mon, 1 Apr 2024 22:49:03 +0900 Subject: [PATCH 4/4] =?UTF-8?q?[Del]=20#259=20-=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=BD=94=EB=93=9C=EC=97=90=EC=84=9C=20=EB=B6=88?= =?UTF-8?q?=ED=95=84=EC=9A=94=ED=95=9C=20=EC=98=88=EC=99=B8=20=EC=B2=B4?= =?UTF-8?q?=ED=81=AC=20=EB=A1=9C=EC=A7=81=20=EC=A4=91=EB=B3=B5=20=ED=99=95?= =?UTF-8?q?=EC=9D=B8=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../moonshot/keyresult/service/KeyResultServiceTest.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/moonshot-api/src/test/java/org/moonshot/keyresult/service/KeyResultServiceTest.java b/moonshot-api/src/test/java/org/moonshot/keyresult/service/KeyResultServiceTest.java index cebb1730..43cb7d57 100644 --- a/moonshot-api/src/test/java/org/moonshot/keyresult/service/KeyResultServiceTest.java +++ b/moonshot-api/src/test/java/org/moonshot/keyresult/service/KeyResultServiceTest.java @@ -155,8 +155,6 @@ static void setUp() { given(testUser.getId()).willReturn(1L); // when, then - assertThatThrownBy(() -> keyResultService.createKeyResult(request, fakeUser.getId())) - .isInstanceOf(BadRequestException.class); assertThatThrownBy(() -> keyResultService.createKeyResult(request, fakeUser.getId())) .isInstanceOf(BadRequestException.class) .hasMessage("허용된 Key Result 개수를 초과하였습니다"); @@ -181,8 +179,6 @@ static void setUp() { given(testUser.getId()).willReturn(1L); // when, then - assertThatThrownBy(() -> keyResultService.createKeyResult(request, fakeUser.getId())) - .isInstanceOf(BadRequestException.class); assertThatThrownBy(() -> keyResultService.createKeyResult(request, fakeUser.getId())) .isInstanceOf(BadRequestException.class) .hasMessage("정상적이지 않은 KeyResult 위치입니다."); @@ -281,8 +277,6 @@ static void setUp() { given(testObjective.getUser()).willReturn(fakeUser); // when, then - assertThatThrownBy(() -> keyResultService.modifyKeyResult(request, fakeUser.getId())) - .isInstanceOf(BadRequestException.class); assertThatThrownBy(() -> keyResultService.modifyKeyResult(request, fakeUser.getId())) .isInstanceOf(BadRequestException.class) .hasMessage("KR 수정시 목표값과 체크인 로그는 필수 입력값입니다.");