diff --git a/moodoodle-api/src/main/java/zzangdol/auth/presentation/AuthController.java b/moodoodle-api/src/main/java/zzangdol/auth/presentation/AuthController.java index 4d4e9e7..fbe167b 100644 --- a/moodoodle-api/src/main/java/zzangdol/auth/presentation/AuthController.java +++ b/moodoodle-api/src/main/java/zzangdol/auth/presentation/AuthController.java @@ -98,13 +98,13 @@ public ResponseDto checkEmailAvailability(@RequestParam String email) { }) @Operation(summary = "토큰 재발급", description = "Refresh Token, Access Token을 재발급합니다.") @PostMapping("/reissue") - public ResponseDto reissue(@RequestParam RefreshTokenRequest request) { + public ResponseDto reissue(@RequestBody RefreshTokenRequest request) { return ResponseDto.onSuccess(authFacade.reissueToken(request)); } @Operation(summary = "로그아웃", description = "사용자의 Refresh Token을 받아 해당 토큰을 무효화합니다.") @DeleteMapping("/sign-out") - public ResponseDto signOut(@RequestParam RefreshTokenRequest request) { + public ResponseDto signOut(@RequestBody RefreshTokenRequest request) { return ResponseDto.onSuccess(authFacade.signOut(request)); } diff --git a/moodoodle-api/src/main/java/zzangdol/diary/business/DiaryFacade.java b/moodoodle-api/src/main/java/zzangdol/diary/business/DiaryFacade.java index d87bc0c..0349ebd 100644 --- a/moodoodle-api/src/main/java/zzangdol/diary/business/DiaryFacade.java +++ b/moodoodle-api/src/main/java/zzangdol/diary/business/DiaryFacade.java @@ -38,8 +38,8 @@ public void deleteDiary(User user, Long diaryId) { diaryCommandService.deleteDiary(user, diaryId); } - public DiaryResponse getDiaryById(User user, Long diaryId) { - return DiaryMapper.toDiaryResponse(diaryQueryService.getDiaryById(user, diaryId)); + public DiaryResponse getDiaryByUser(User user, Long diaryId) { + return DiaryMapper.toDiaryResponse(diaryQueryService.getDiaryByUser(user, diaryId)); } public DiaryListResponse getMonthlyDiariesByUser(User user, int year, int month) { diff --git a/moodoodle-api/src/main/java/zzangdol/diary/implement/DiaryQueryService.java b/moodoodle-api/src/main/java/zzangdol/diary/implement/DiaryQueryService.java index 2aef23f..1340459 100644 --- a/moodoodle-api/src/main/java/zzangdol/diary/implement/DiaryQueryService.java +++ b/moodoodle-api/src/main/java/zzangdol/diary/implement/DiaryQueryService.java @@ -6,7 +6,7 @@ public interface DiaryQueryService { - Diary getDiaryById(User user, Long diaryId); + Diary getDiaryByUser(User user, Long diaryId); List getMonthlyDiariesByUser(User user, int year, int month); diff --git a/moodoodle-api/src/main/java/zzangdol/diary/implement/DiaryQueryServiceImpl.java b/moodoodle-api/src/main/java/zzangdol/diary/implement/DiaryQueryServiceImpl.java index d526a36..1ec3abe 100644 --- a/moodoodle-api/src/main/java/zzangdol/diary/implement/DiaryQueryServiceImpl.java +++ b/moodoodle-api/src/main/java/zzangdol/diary/implement/DiaryQueryServiceImpl.java @@ -20,18 +20,22 @@ public class DiaryQueryServiceImpl implements DiaryQueryService { private final DiaryQueryRepository diaryQueryRepository; @Override - public Diary getDiaryById(User user, Long diaryId) { + public Diary getDiaryByUser(User user, Long diaryId) { Diary diary = diaryRepository.findById(diaryId) .orElseThrow(() -> DiaryNotFoundException.EXCEPTION); - if (!diary.getUser().equals(user)) { - throw DiaryAccessDeniedException.EXCEPTION; - } + checkDiaryOwnership(user, diary); return diary; } @Override public List getMonthlyDiariesByUser(User user, int year, int month) { - return diaryQueryRepository.findDiariesByUserAndMonth(user.getId(), year, month); + return diaryQueryRepository.findDiariesByUserAndYearAndMonth(user.getId(), year, month); + } + + private void checkDiaryOwnership(User user, Diary diary) { + if (!diary.getUser().getId().equals(user.getId())) { + throw DiaryAccessDeniedException.EXCEPTION; + } } } diff --git a/moodoodle-api/src/main/java/zzangdol/diary/implement/ImageColorAnalyzer.java b/moodoodle-api/src/main/java/zzangdol/diary/implement/ImageColorAnalyzer.java index abbd85c..ddeb482 100644 --- a/moodoodle-api/src/main/java/zzangdol/diary/implement/ImageColorAnalyzer.java +++ b/moodoodle-api/src/main/java/zzangdol/diary/implement/ImageColorAnalyzer.java @@ -14,7 +14,7 @@ public String analyzeAverageColorAsHex(String imageUrl) { int[] averageColor = getAverageColor(imageUrl); return rgbToHex(averageColor[0], averageColor[1], averageColor[2]); } catch (Exception e) { - return "#ffffff"; + return "#FFFFFF"; } } diff --git a/moodoodle-api/src/main/java/zzangdol/diary/presentation/DiaryController.java b/moodoodle-api/src/main/java/zzangdol/diary/presentation/DiaryController.java index 871f620..5626bae 100644 --- a/moodoodle-api/src/main/java/zzangdol/diary/presentation/DiaryController.java +++ b/moodoodle-api/src/main/java/zzangdol/diary/presentation/DiaryController.java @@ -86,9 +86,9 @@ public ResponseDto deleteDiary(@AuthUser User user, description = "지정된 ID의 일기를 조회합니다. 상세 정보를 반환합니다." ) @GetMapping("/{diaryId}") - public ResponseDto getDiaryById(@AuthUser User user, + public ResponseDto getDiaryByUser(@AuthUser User user, @PathVariable("diaryId") Long diaryId) { - return ResponseDto.onSuccess(diaryFacade.getDiaryById(user, diaryId)); + return ResponseDto.onSuccess(diaryFacade.getDiaryByUser(user, diaryId)); } @ApiErrorCodeExample({ diff --git a/moodoodle-api/src/test/java/zzangdol/diary/implement/DiaryCommandServiceTest.java b/moodoodle-api/src/test/java/zzangdol/diary/implement/DiaryCommandServiceTest.java index b3c30d1..6b1ed4e 100644 --- a/moodoodle-api/src/test/java/zzangdol/diary/implement/DiaryCommandServiceTest.java +++ b/moodoodle-api/src/test/java/zzangdol/diary/implement/DiaryCommandServiceTest.java @@ -80,13 +80,13 @@ void createDiary() { DiaryCreateRequest request = buildValidDiaryCreateRequest(LocalDateTime.of(2024, 1, 1, 0, 0)); // when - Diary createdDiary = diaryCommandService.createDiary(user, request, "FFFFFF", emotions); + Diary createdDiary = diaryCommandService.createDiary(user, request, "#FFFFFF", emotions); // then assertThat(createdDiary).isNotNull(); assertThat(createdDiary.getId()).isNotNull(); assertThat(createdDiary.getContent()).isEqualTo("content"); - assertThat(createdDiary.getPainting().getColor()).isEqualTo("FFFFFF"); + assertThat(createdDiary.getPainting().getColor()).isEqualTo("#FFFFFF"); assertThat(createdDiary.getDate()).isEqualTo(LocalDateTime.of(2024, 1, 1, 0, 0)); assertThat(createdDiary.getDiaryEmotions()) @@ -107,7 +107,7 @@ void shouldNotCreateDiaryWithFutureDate() { .build(); // when & then - assertThatThrownBy(() -> diaryCommandService.createDiary(user, request, "FFFFFF", emotions)) + assertThatThrownBy(() -> diaryCommandService.createDiary(user, request, "#FFFFFF", emotions)) .isInstanceOf(DiaryDateOutOfBoundsException.class) .hasMessageContaining("일기는 오늘 날짜 이후로 생성할 수 없습니다."); } @@ -117,10 +117,10 @@ void shouldNotCreateDiaryWithFutureDate() { void shouldNotCreateDiaryWithDuplicatedDate() { // given DiaryCreateRequest request = buildValidDiaryCreateRequest(LocalDateTime.of(2024, 1, 1, 0, 0)); - diaryCommandService.createDiary(user, request, "FFFFFF", emotions); + diaryCommandService.createDiary(user, request, "#FFFFFF", emotions); // when & then - assertThatThrownBy(() -> diaryCommandService.createDiary(user, request, "FFFFFF", emotions)) + assertThatThrownBy(() -> diaryCommandService.createDiary(user, request, "#FFFFFF", emotions)) .isInstanceOf(DiaryDuplicateDateException.class) .hasMessageContaining("해당 날짜에 이미 일기가 존재합니다."); } @@ -130,7 +130,7 @@ void shouldNotCreateDiaryWithDuplicatedDate() { void updateDiary() { // given DiaryCreateRequest createRequest = buildValidDiaryCreateRequest(LocalDateTime.of(2024, 1, 1, 0, 0)); - Diary createdDiary = diaryCommandService.createDiary(user, createRequest, "FFFFFF", emotions); + Diary createdDiary = diaryCommandService.createDiary(user, createRequest, "#FFFFFF", emotions); DiaryUpdateRequest updateRequest = buildValidDiaryUpdateRequest( "updated content", @@ -144,7 +144,7 @@ void updateDiary() { assertThat(updatedDiary).isNotNull(); assertThat(updatedDiary.getId()).isNotNull(); assertThat(updatedDiary.getContent()).isEqualTo("updated content"); - assertThat(updatedDiary.getPainting().getColor()).isEqualTo("FFFFFF"); + assertThat(updatedDiary.getPainting().getColor()).isEqualTo("#FFFFFF"); assertThat(updatedDiary.getDate()).isEqualTo(LocalDateTime.of(2023, 1, 1, 0, 0)); assertThat(createdDiary.getDiaryEmotions()) @@ -158,7 +158,7 @@ void updateDiary() { void updateDiaryContentOnly() { // given DiaryCreateRequest createRequest = buildValidDiaryCreateRequest(LocalDateTime.of(2024, 1, 1, 0, 0)); - Diary createdDiary = diaryCommandService.createDiary(user, createRequest, "FFFFFF", emotions); + Diary createdDiary = diaryCommandService.createDiary(user, createRequest, "#FFFFFF", emotions); DiaryUpdateRequest updateRequest = buildValidDiaryUpdateRequest("updated content", null); @@ -169,7 +169,7 @@ void updateDiaryContentOnly() { assertThat(updatedDiary).isNotNull(); assertThat(updatedDiary.getId()).isNotNull(); assertThat(updatedDiary.getContent()).isEqualTo("updated content"); - assertThat(updatedDiary.getPainting().getColor()).isEqualTo("FFFFFF"); + assertThat(updatedDiary.getPainting().getColor()).isEqualTo("#FFFFFF"); assertThat(updatedDiary.getDate()).isEqualTo(LocalDateTime.of(2024, 1, 1, 0, 0)); assertThat(createdDiary.getDiaryEmotions()) @@ -183,7 +183,7 @@ void updateDiaryContentOnly() { void updateDiaryDateOnly() { // given DiaryCreateRequest createRequest = buildValidDiaryCreateRequest(LocalDateTime.of(2024, 1, 1, 0, 0)); - Diary createdDiary = diaryCommandService.createDiary(user, createRequest, "FFFFFF", emotions); + Diary createdDiary = diaryCommandService.createDiary(user, createRequest, "#FFFFFF", emotions); DiaryUpdateRequest updateRequest = buildValidDiaryUpdateRequest(null, LocalDateTime.of(2023, 1, 1, 0, 0)); @@ -194,7 +194,7 @@ void updateDiaryDateOnly() { assertThat(updatedDiary).isNotNull(); assertThat(updatedDiary.getId()).isNotNull(); assertThat(updatedDiary.getContent()).isEqualTo("content"); - assertThat(updatedDiary.getPainting().getColor()).isEqualTo("FFFFFF"); + assertThat(updatedDiary.getPainting().getColor()).isEqualTo("#FFFFFF"); assertThat(updatedDiary.getDate()).isEqualTo(LocalDateTime.of(2023, 1, 1, 0, 0)); assertThat(createdDiary.getDiaryEmotions()) @@ -221,7 +221,7 @@ void throwExceptionWhenUPDATENonExistentDiary() { void shouldNotUpdateDiaryWithFutureDate() { // given DiaryCreateRequest createRequest = buildValidDiaryCreateRequest(LocalDateTime.of(2024, 1, 1, 0, 0)); - Diary createdDiary = diaryCommandService.createDiary(user, createRequest, "FFFFFF", emotions); + Diary createdDiary = diaryCommandService.createDiary(user, createRequest, "#FFFFFF", emotions); DiaryUpdateRequest updateRequest = buildValidDiaryUpdateRequest(null, LocalDateTime.now().plusDays(1)); @@ -236,10 +236,10 @@ void shouldNotUpdateDiaryWithFutureDate() { void shouldNotUpdateDiaryWithDuplicatedDate() { // given DiaryCreateRequest createRequest1 = buildValidDiaryCreateRequest(LocalDateTime.of(2024, 1, 1, 0, 0)); - diaryCommandService.createDiary(user, createRequest1, "FFFFFF", emotions); + diaryCommandService.createDiary(user, createRequest1, "#FFFFFF", emotions); DiaryCreateRequest createRequest2 = buildValidDiaryCreateRequest(LocalDateTime.of(2023, 1, 1, 0, 0)); - Diary createdDiary = diaryCommandService.createDiary(user, createRequest2, "FFFFFF", emotions); + Diary createdDiary = diaryCommandService.createDiary(user, createRequest2, "#FFFFFF", emotions); DiaryUpdateRequest updateRequest = buildValidDiaryUpdateRequest(null, LocalDateTime.of(2024, 1, 1, 0, 0)); @@ -257,7 +257,7 @@ void shouldThrowAccessDeniedWhenUpdatingOtherUsersDiary() { userRepository.save(otherUser); DiaryCreateRequest createRequest = buildValidDiaryCreateRequest(LocalDateTime.of(2024, 1, 1, 0, 0)); - Diary diary = diaryCommandService.createDiary(user, createRequest, "FFFFFF", emotions); + Diary diary = diaryCommandService.createDiary(user, createRequest, "#FFFFFF", emotions); DiaryUpdateRequest updateRequest = buildValidDiaryUpdateRequest("updated content", LocalDateTime.now()); @@ -273,7 +273,7 @@ void shouldThrowAccessDeniedWhenUpdatingOtherUsersDiary() { void deleteDiarySuccessfully() { // given DiaryCreateRequest createRequest = buildValidDiaryCreateRequest(LocalDateTime.of(2024, 1, 1, 0, 0)); - Diary createdDiary = diaryCommandService.createDiary(user, createRequest, "FFFFFF", emotions); + Diary createdDiary = diaryCommandService.createDiary(user, createRequest, "#FFFFFF", emotions); // when diaryCommandService.deleteDiary(user, createdDiary.getId()); @@ -304,7 +304,7 @@ void shouldThrowAccessDeniedWhenDeletingOtherUsersDiary() { userRepository.save(otherUser); DiaryCreateRequest createRequest = buildValidDiaryCreateRequest(LocalDateTime.of(2024, 1, 1, 0, 0)); - Diary diary = diaryCommandService.createDiary(user, createRequest, "FFFFFF", emotions); + Diary diary = diaryCommandService.createDiary(user, createRequest, "#FFFFFF", emotions); // when & then assertThrows(DiaryAccessDeniedException.class, () -> { diff --git a/moodoodle-api/src/test/java/zzangdol/diary/implement/DiaryQueryServiceTest.java b/moodoodle-api/src/test/java/zzangdol/diary/implement/DiaryQueryServiceTest.java new file mode 100644 index 0000000..bfd3e44 --- /dev/null +++ b/moodoodle-api/src/test/java/zzangdol/diary/implement/DiaryQueryServiceTest.java @@ -0,0 +1,124 @@ +package zzangdol.diary.implement; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.time.LocalDateTime; +import java.util.List; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import zzangdol.diary.dao.DiaryRepository; +import zzangdol.diary.domain.Diary; +import zzangdol.exception.custom.DiaryAccessDeniedException; +import zzangdol.exception.custom.DiaryNotFoundException; +import zzangdol.user.dao.UserRepository; +import zzangdol.user.domain.User; + +@SpringBootTest +class DiaryQueryServiceTest { + + @Autowired + private DiaryQueryService diaryQueryService; + + @Autowired + private UserRepository userRepository; + + @Autowired + private DiaryRepository diaryRepository; + + private User user; + + @BeforeEach + void setUp() { + diaryRepository.deleteAll(); + userRepository.deleteAll(); + user = User.builder().build(); + userRepository.save(user); + } + + @AfterEach + void tearDown() { + diaryRepository.deleteAllInBatch(); + userRepository.deleteAllInBatch(); + } + + @DisplayName("특정 일기를 조회한다.") + @Test + void getDiaryByUser() { + // given + Diary diary = buildDiary(LocalDateTime.of(2024, 4, 1, 0, 0)); + diary = diaryRepository.save(diary); + + // when + Diary result = diaryQueryService.getDiaryByUser(user, diary.getId()); + + // then + assertThat(result).isNotNull(); + assertThat(result.getId()).isEqualTo(diary.getId()); + assertThat(result.getContent()).isEqualTo("content"); + assertThat(result.getDate()).isEqualTo(LocalDateTime.of(2024, 4, 1, 0, 0)); + } + + @DisplayName("특정 사용자의 특정 연도와 월에 대한 일기 목록을 조회한다.") + @Test + void getMonthlyDiariesByUser() { + // given + Diary diary1 = buildDiary(LocalDateTime.of(2024, 4, 1, 0, 0)); + Diary diary2 = buildDiary(LocalDateTime.of(2024, 4, 30, 23, 59)); + Diary diary3 = buildDiary(LocalDateTime.of(2024, 5, 1, 0, 0)); + Diary diary4 = buildDiary(LocalDateTime.of(2024, 3, 31, 23, 59)); + diaryRepository.saveAll(List.of(diary1, diary2, diary3, diary4)); + + int year = 2024; + int month = 4; + + // when + List result = diaryQueryService.getMonthlyDiariesByUser(user, year, month); + + // then + assertThat(result).isNotNull(); + assertThat(result).hasSize(2); + assertThat(result).extracting("date") + .containsExactlyInAnyOrder( + LocalDateTime.of(2024, 4, 1, 0, 0), + LocalDateTime.of(2024, 4, 30, 23, 59)); + } + + @DisplayName("다른 사용자의 일기를 조회하려 할 때 접근 거부 예외를 발생시킨다.") + @Test + void accessDeniedWhenUserIsNotOwner() { + // given + Diary diary = buildDiary(LocalDateTime.of(2024, 4, 1, 0, 0)); + diaryRepository.save(diary); + User otherUser = User.builder().build(); + + // when & then + assertThrows(DiaryAccessDeniedException.class, () -> { + diaryQueryService.getDiaryByUser(otherUser, diary.getId()); + }); + } + + @Test + @DisplayName("존재하지 않는 일기를 조회하려 할 때 예외를 발생시킨다.") + void throwExceptionWhenGetNonExistentDiary() { + // given + Long nonExistentDiaryId = 999L; // 존재하지 않는 ID + + // when & then + assertThrows(DiaryNotFoundException.class, () -> { + diaryQueryService.getDiaryByUser(user, nonExistentDiaryId); + }); + } + + private Diary buildDiary(LocalDateTime date) { + return Diary.builder() + .user(user) + .content("content") + .date(date) + .build(); + } +} \ No newline at end of file diff --git a/moodoodle-api/src/test/java/zzangdol/diary/presentation/DiaryControllerTest.java b/moodoodle-api/src/test/java/zzangdol/diary/presentation/DiaryControllerTest.java index 2946c99..ef363c7 100644 --- a/moodoodle-api/src/test/java/zzangdol/diary/presentation/DiaryControllerTest.java +++ b/moodoodle-api/src/test/java/zzangdol/diary/presentation/DiaryControllerTest.java @@ -2,11 +2,13 @@ import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; @@ -15,6 +17,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import java.time.LocalDateTime; import java.time.LocalTime; +import java.util.Arrays; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -26,6 +29,8 @@ import zzangdol.diary.business.DiaryFacade; import zzangdol.diary.presentation.dto.request.DiaryCreateRequest; import zzangdol.diary.presentation.dto.request.DiaryUpdateRequest; +import zzangdol.diary.presentation.dto.response.DiaryListResponse; +import zzangdol.diary.presentation.dto.response.DiaryResponse; import zzangdol.global.annotation.AuthenticationArgumentResolver; import zzangdol.user.domain.AuthProvider; import zzangdol.user.domain.Role; @@ -208,4 +213,87 @@ void deleteDiary() throws Exception { verify(diaryFacade).deleteDiary(user, diaryId); } + @WithMockUser(username = "회원", roles = {"MEMBER"}) + @DisplayName("[GET] 일기 단건 조회 테스트 - 정상") + @Test + void getDiaryByUser() throws Exception { + // given + DiaryResponse diaryResponse = DiaryResponse.builder() + .id(1L) + .date(LocalDateTime.of(2024, 1, 1, 0, 0)) + .content("content") + .imageUrl("imageUrl") + .color("#FFFFFF") + .build(); + + User user = User.builder() + .email("test@example.com") + .password("password") + .role(Role.MEMBER) + .authProvider(AuthProvider.DEFAULT) + .notificationTime(LocalTime.now()) + .build(); + + when(diaryFacade.getDiaryByUser(any(User.class), eq(1L))).thenReturn(diaryResponse); + when(authenticationArgumentResolver.resolveArgument(any(), any(), any(), any())).thenReturn(user); + when(authenticationArgumentResolver.supportsParameter(any())).thenReturn(true); + + // when & then + mockMvc.perform(get("/api/diaries/{diaryId}", 1L) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.result.id").value(1L)) + .andExpect(jsonPath("$.result.content").value("content")) + .andExpect(jsonPath("$.result.imageUrl").value("imageUrl")) + .andExpect(jsonPath("$.result.color").value("#FFFFFF")); + } + + @WithMockUser(username = "회원", roles = {"MEMBER"}) + @DisplayName("[GET] 월간 일기 목록 조회 테스트 - 정상") + @Test + void getMonthlyDiaries() throws Exception { + // given + DiaryListResponse diaryListResponse = DiaryListResponse.builder() + .diaries(Arrays.asList( + DiaryResponse.builder() + .id(1L) + .date(LocalDateTime.of(2024, 4, 1, 0, 0)) + .content("content1") + .imageUrl("imageUrl1") + .color("#111111") + .build(), + DiaryResponse.builder() + .id(2L) + .date(LocalDateTime.of(2024, 4, 20, 0, 0)) + .content("content2") + .imageUrl("imageUrl2") + .color("#222222") + .build() + )) + .build(); + + User user = User.builder() + .email("test@example.com") + .password("password") + .role(Role.MEMBER) + .authProvider(AuthProvider.DEFAULT) + .notificationTime(LocalTime.now()) + .build(); + + when(diaryFacade.getMonthlyDiariesByUser(any(User.class), eq(2024), eq(4))).thenReturn(diaryListResponse); + when(authenticationArgumentResolver.resolveArgument(any(), any(), any(), any())).thenReturn(user); + when(authenticationArgumentResolver.supportsParameter(any())).thenReturn(true); + + // when & then + mockMvc.perform(get("/api/diaries") + .param("year", "2024") + .param("month", "4") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.result.diaries[0].id").value(1L)) + .andExpect(jsonPath("$.result.diaries[0].content").value("content1")) + .andExpect(jsonPath("$.result.diaries[1].id").value(2L)) + .andExpect(jsonPath("$.result.diaries[1].content").value("content2")); + } + } \ No newline at end of file diff --git a/moodoodle-domain/src/main/java/zzangdol/diary/dao/querydsl/DiaryQueryRepository.java b/moodoodle-domain/src/main/java/zzangdol/diary/dao/querydsl/DiaryQueryRepository.java index 5653b93..273dbeb 100644 --- a/moodoodle-domain/src/main/java/zzangdol/diary/dao/querydsl/DiaryQueryRepository.java +++ b/moodoodle-domain/src/main/java/zzangdol/diary/dao/querydsl/DiaryQueryRepository.java @@ -5,6 +5,6 @@ public interface DiaryQueryRepository { - List findDiariesByUserAndMonth(Long userId, int year, int month); + List findDiariesByUserAndYearAndMonth(Long userId, int year, int month); } diff --git a/moodoodle-domain/src/main/java/zzangdol/diary/dao/querydsl/DiaryQueryRepositoryImpl.java b/moodoodle-domain/src/main/java/zzangdol/diary/dao/querydsl/DiaryQueryRepositoryImpl.java index 15140d9..aab309a 100644 --- a/moodoodle-domain/src/main/java/zzangdol/diary/dao/querydsl/DiaryQueryRepositoryImpl.java +++ b/moodoodle-domain/src/main/java/zzangdol/diary/dao/querydsl/DiaryQueryRepositoryImpl.java @@ -13,7 +13,7 @@ public class DiaryQueryRepositoryImpl implements DiaryQueryRepository { private final JPAQueryFactory queryFactory; - public List findDiariesByUserAndMonth(Long userId, int year, int month) { + public List findDiariesByUserAndYearAndMonth(Long userId, int year, int month) { QDiary qDiary = QDiary.diary; return queryFactory.selectFrom(qDiary) diff --git a/moodoodle-domain/src/test/java/zzangdol/DomainTestConfig.java b/moodoodle-domain/src/test/java/zzangdol/DomainTestConfig.java new file mode 100644 index 0000000..0d97bfc --- /dev/null +++ b/moodoodle-domain/src/test/java/zzangdol/DomainTestConfig.java @@ -0,0 +1,9 @@ +package zzangdol; + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; + +@EnableJpaRepositories +@SpringBootApplication +class DomainTestConfig { +} diff --git a/moodoodle-domain/src/test/java/zzangdol/config/TestQueryDslConfig.java b/moodoodle-domain/src/test/java/zzangdol/config/TestQueryDslConfig.java new file mode 100644 index 0000000..dd52426 --- /dev/null +++ b/moodoodle-domain/src/test/java/zzangdol/config/TestQueryDslConfig.java @@ -0,0 +1,27 @@ +package zzangdol.config; + +import com.querydsl.jpa.impl.JPAQueryFactory; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import zzangdol.diary.dao.querydsl.DiaryQueryRepository; +import zzangdol.diary.dao.querydsl.DiaryQueryRepositoryImpl; + +@TestConfiguration +public class TestQueryDslConfig { + + @PersistenceContext + private EntityManager entityManager; + + @Bean + public JPAQueryFactory jpaQueryFactory() { + return new JPAQueryFactory(entityManager); + } + + @Bean + public DiaryQueryRepository diaryQueryRepository() { + return new DiaryQueryRepositoryImpl(jpaQueryFactory()); + } + +} diff --git a/moodoodle-domain/src/test/java/zzangdol/diary/dao/querydsl/DiaryQueryRepositoryTest.java b/moodoodle-domain/src/test/java/zzangdol/diary/dao/querydsl/DiaryQueryRepositoryTest.java new file mode 100644 index 0000000..15ca90c --- /dev/null +++ b/moodoodle-domain/src/test/java/zzangdol/diary/dao/querydsl/DiaryQueryRepositoryTest.java @@ -0,0 +1,81 @@ +package zzangdol.diary.dao.querydsl; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.LocalDateTime; +import java.util.List; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; +import zzangdol.config.TestQueryDslConfig; +import zzangdol.diary.dao.DiaryRepository; +import zzangdol.diary.domain.Diary; +import zzangdol.user.dao.UserRepository; +import zzangdol.user.domain.User; + +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +@Import(TestQueryDslConfig.class) +@DataJpaTest +class DiaryQueryRepositoryTest { + + @Autowired + private DiaryQueryRepository diaryQueryRepository; + + @Autowired + private UserRepository userRepository; + + @Autowired + private DiaryRepository diaryRepository; + + private User user; + + @BeforeEach + void setUp() { + diaryRepository.deleteAll(); + userRepository.deleteAll(); + user = User.builder().build(); + userRepository.save(user); + } + + @AfterEach + void tearDown() { + diaryRepository.deleteAllInBatch(); + userRepository.deleteAllInBatch(); + } + + @DisplayName("특정 사용자의 특정 연도와 월에 대한 일기 목록을 조회한다.") + @Test + void findDiariesByUserAndYearAndMonth() { + // given + Diary diary1 = buildDiary(LocalDateTime.of(2024, 4, 1, 0, 0)); + Diary diary2 = buildDiary(LocalDateTime.of(2024, 4, 30, 23, 59)); + Diary diary3 = buildDiary(LocalDateTime.of(2024, 5, 1, 0, 0)); + Diary diary4 = buildDiary(LocalDateTime.of(2024, 3, 31, 23, 59)); + diaryRepository.saveAll(List.of(diary1, diary2, diary3, diary4)); + + Long userId = user.getId(); + int year = 2024; + int month = 4; + + // when + List result = diaryQueryRepository.findDiariesByUserAndYearAndMonth(userId, year, month); + + // then + assertThat(result).isNotNull(); + assertThat(result).hasSize(2); + } + + private Diary buildDiary(LocalDateTime date) { + return Diary.builder() + .user(user) + .content("content") + .date(date) + .build(); + } + +} \ No newline at end of file diff --git a/moodoodle-domain/src/test/resources/application.yml b/moodoodle-domain/src/test/resources/application.yml new file mode 100644 index 0000000..edd33d8 --- /dev/null +++ b/moodoodle-domain/src/test/resources/application.yml @@ -0,0 +1,12 @@ +spring: + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://localhost:3306/moodoodle?useSSL=true&useUnicode=true&serverTimezone=Asia/Seoul + username: admin + password: 12345678 + redis: + host: localhost + port: 6379 + jpa: + hibernate: + ddl-auto: create \ No newline at end of file