|
3 | 3 | import back.kalender.domain.artist.entity.ArtistFollowTmp; |
4 | 4 | import back.kalender.domain.artist.entity.ArtistTmp; |
5 | 5 | import back.kalender.domain.artist.repository.ArtistFollowRepositoryTmp; |
| 6 | +import back.kalender.domain.schedule.dto.response.DailyScheduleItem; |
| 7 | +import back.kalender.domain.schedule.dto.response.DailySchedulesResponse; |
6 | 8 | import back.kalender.domain.schedule.dto.response.MonthlyScheduleItem; |
7 | 9 | import back.kalender.domain.schedule.dto.response.MonthlySchedulesResponse; |
8 | 10 | import back.kalender.domain.schedule.entity.ScheduleCategory; |
9 | 11 | import back.kalender.domain.schedule.repository.ScheduleRepository; |
| 12 | +import back.kalender.global.exception.ErrorCode; |
| 13 | +import back.kalender.global.exception.ServiceException; |
10 | 14 | import org.junit.jupiter.api.DisplayName; |
11 | 15 | import org.junit.jupiter.api.Test; |
12 | 16 | import org.junit.jupiter.api.extension.ExtendWith; |
|
21 | 25 | import java.util.Optional; |
22 | 26 |
|
23 | 27 | import static org.assertj.core.api.Assertions.assertThat; |
| 28 | +import static org.assertj.core.api.Assertions.assertThatThrownBy; |
24 | 29 | import static org.mockito.ArgumentMatchers.any; |
25 | 30 | import static org.mockito.ArgumentMatchers.eq; |
26 | 31 | import static org.mockito.BDDMockito.given; |
| 32 | +import static org.mockito.Mockito.times; |
27 | 33 | import static org.mockito.Mockito.verify; |
28 | 34 |
|
29 | 35 | @ExtendWith(MockitoExtension.class) |
@@ -95,6 +101,20 @@ private MonthlyScheduleItem createDto(Long id, Long artistId, String artistName, |
95 | 101 | ); |
96 | 102 | } |
97 | 103 |
|
| 104 | + @Test |
| 105 | + @DisplayName("월별 전체 조회 - 실패 (유효하지 않은 월 입력)") |
| 106 | + void getFollowingSchedules_Fail_InvalidMonth() { |
| 107 | + Long userId = 1L; |
| 108 | + int year = 2025; |
| 109 | + int invalidMonth = 13; |
| 110 | + |
| 111 | + assertThatThrownBy(() -> |
| 112 | + scheduleServiceImpl.getFollowingSchedules(userId, year, invalidMonth) |
| 113 | + ) |
| 114 | + .isInstanceOf(ServiceException.class) |
| 115 | + .hasMessageContaining(ErrorCode.INVALID_INPUT_VALUE.getMessage()); |
| 116 | + } |
| 117 | + |
98 | 118 | @Test |
99 | 119 | @DisplayName("여러 아티스트 중 특정 아티스트(BTS)만 조회 시, 정확히 해당 ID로만 필터링하여 요청한다.") |
100 | 120 | void getArtistSchedules_FilterVerification() { |
@@ -127,4 +147,143 @@ void getArtistSchedules_FilterVerification() { |
127 | 147 |
|
128 | 148 | verify(artistFollowRepository).existsByUserIdAndArtistId(userId, btsId); |
129 | 149 | } |
| 150 | + |
| 151 | + @Test |
| 152 | + @DisplayName("월별 개별 조회 - 실패 (유효하지 않은 월 입력)") |
| 153 | + void getArtistSchedules_Fail_InvalidMonth() { |
| 154 | + Long userId = 1L; |
| 155 | + Long artistId = 1L; |
| 156 | + int year = 2025; |
| 157 | + int invalidMonth = 0; // 1~12 범위를 벗어남 |
| 158 | + |
| 159 | + assertThatThrownBy(() -> |
| 160 | + scheduleServiceImpl.getSchedulesPerArtist(userId, artistId, year, invalidMonth) |
| 161 | + ) |
| 162 | + .isInstanceOf(ServiceException.class) |
| 163 | + .hasMessageContaining(ErrorCode.INVALID_INPUT_VALUE.getMessage()); |
| 164 | + } |
| 165 | + |
| 166 | + @Test |
| 167 | + @DisplayName("월별 개별 조회 - 실패 (팔로우하지 않은 아티스트 요청)") |
| 168 | + void getArtistSchedules_Fail_NotFollowed() { |
| 169 | + Long userId = 1L; |
| 170 | + Long notFollowedId = 99L; |
| 171 | + int year = 2025; |
| 172 | + int month = 11; |
| 173 | + |
| 174 | + given(artistFollowRepository.existsByUserIdAndArtistId(userId, notFollowedId)) |
| 175 | + .willReturn(false); |
| 176 | + |
| 177 | + assertThatThrownBy(() -> |
| 178 | + scheduleServiceImpl.getSchedulesPerArtist(userId, notFollowedId, year, month) |
| 179 | + ) |
| 180 | + .isInstanceOf(ServiceException.class) |
| 181 | + .hasMessageContaining(ErrorCode.ARTIST_NOT_FOLLOWED.getMessage()); |
| 182 | + |
| 183 | + verify(scheduleRepository, times(0)).findMonthlySchedules(any(), any(), any()); |
| 184 | + } |
| 185 | + @Test |
| 186 | + @DisplayName("하루 상세 조회 - 성공 (전체 아티스트)") |
| 187 | + void getDailySchedules_Success_AllArtists() { |
| 188 | + Long userId = 1L; |
| 189 | + String dateStr = "2025-12-15"; |
| 190 | + |
| 191 | + ArtistTmp bts = new ArtistTmp("BTS", "img"); |
| 192 | + ReflectionTestUtils.setField(bts, "id", 1L); |
| 193 | + ArtistFollowTmp f1 = new ArtistFollowTmp(userId, bts); |
| 194 | + |
| 195 | + ArtistTmp bp = new ArtistTmp("BP", "img"); |
| 196 | + ReflectionTestUtils.setField(bp, "id", 2L); |
| 197 | + ArtistFollowTmp f2 = new ArtistFollowTmp(userId, bp); |
| 198 | + |
| 199 | + given(artistFollowRepository.findAllByUserId(userId)) |
| 200 | + .willReturn(List.of(f1, f2)); |
| 201 | + |
| 202 | + List<DailyScheduleItem> dbResult = List.of( |
| 203 | + createDailyDto(100L, "BTS", "콘서트"), |
| 204 | + createDailyDto(101L, "BP", "방송") |
| 205 | + ); |
| 206 | + |
| 207 | + given(scheduleRepository.findDailySchedules(any(), any(), any())) |
| 208 | + .willReturn(dbResult); |
| 209 | + |
| 210 | + DailySchedulesResponse response = scheduleServiceImpl.getDailySchedules(userId, dateStr, Optional.empty()); |
| 211 | + |
| 212 | + assertThat(response.dailySchedules()).hasSize(2); |
| 213 | + |
| 214 | + verify(scheduleRepository).findDailySchedules( |
| 215 | + eq(List.of(1L, 2L)), |
| 216 | + any(), |
| 217 | + any() |
| 218 | + ); |
| 219 | + } |
| 220 | + |
| 221 | + @Test |
| 222 | + @DisplayName("하루 상세 조회 - 성공 (특정 아티스트 필터링)") |
| 223 | + void getDailySchedules_Success_SpecificArtist() { |
| 224 | + Long userId = 1L; |
| 225 | + Long targetId = 1L; // BTS |
| 226 | + String dateStr = "2025-12-15"; |
| 227 | + |
| 228 | + given(artistFollowRepository.existsByUserIdAndArtistId(userId, targetId)) |
| 229 | + .willReturn(true); |
| 230 | + |
| 231 | + List<DailyScheduleItem> dbResult = List.of( |
| 232 | + createDailyDto(100L, "BTS", "콘서트") |
| 233 | + ); |
| 234 | + |
| 235 | + given(scheduleRepository.findDailySchedules(any(), any(), any())) |
| 236 | + .willReturn(dbResult); |
| 237 | + |
| 238 | + DailySchedulesResponse response = scheduleServiceImpl.getDailySchedules(userId, dateStr, Optional.of(targetId)); |
| 239 | + |
| 240 | + assertThat(response.dailySchedules()).hasSize(1); |
| 241 | + assertThat(response.dailySchedules().get(0).artistName()).isEqualTo("BTS"); |
| 242 | + |
| 243 | + verify(scheduleRepository).findDailySchedules( |
| 244 | + eq(List.of(targetId)), |
| 245 | + any(), |
| 246 | + any() |
| 247 | + ); |
| 248 | + verify(artistFollowRepository, times(0)).findAllByUserId(any()); |
| 249 | + } |
| 250 | + |
| 251 | + @Test |
| 252 | + @DisplayName("하루 상세 조회 - 실패 (날짜 포맷 오류)") |
| 253 | + void getDailySchedules_Fail_InvalidDate() { |
| 254 | + Long userId = 1L; |
| 255 | + String invalidDate = "2025/12/15"; |
| 256 | + |
| 257 | + assertThatThrownBy(() -> |
| 258 | + scheduleServiceImpl.getDailySchedules(userId, invalidDate, Optional.empty()) |
| 259 | + ) |
| 260 | + .isInstanceOf(ServiceException.class) |
| 261 | + .hasMessageContaining(ErrorCode.INVALID_INPUT_VALUE.getMessage()); |
| 262 | + } |
| 263 | + |
| 264 | + @Test |
| 265 | + @DisplayName("하루 상세 조회 - 실패 (팔로우하지 않은 아티스트 요청)") |
| 266 | + void getDailySchedules_Fail_NotFollowed() { |
| 267 | + Long userId = 1L; |
| 268 | + Long notFollowedId = 99L; |
| 269 | + String dateStr = "2025-12-15"; |
| 270 | + |
| 271 | + given(artistFollowRepository.existsByUserIdAndArtistId(userId, notFollowedId)) |
| 272 | + .willReturn(false); |
| 273 | + |
| 274 | + assertThatThrownBy(() -> |
| 275 | + scheduleServiceImpl.getDailySchedules(userId, dateStr, Optional.of(notFollowedId)) |
| 276 | + ) |
| 277 | + .isInstanceOf(ServiceException.class) |
| 278 | + .hasMessageContaining(ErrorCode.ARTIST_NOT_FOLLOWED.getMessage()); |
| 279 | + } |
| 280 | + |
| 281 | + private DailyScheduleItem createDailyDto(Long id, String artistName, String title) { |
| 282 | + return new DailyScheduleItem( |
| 283 | + id, artistName, title, |
| 284 | + ScheduleCategory.CONCERT, |
| 285 | + LocalDateTime.now(), |
| 286 | + null, null, "장소" |
| 287 | + ); |
| 288 | + } |
130 | 289 | } |
0 commit comments