|
| 1 | + |
1 | 2 | import com.back.koreaTravelGuide.KoreaTravelGuideApplication |
2 | 3 | import com.back.koreaTravelGuide.config.TestConfig |
3 | | -import com.back.koreaTravelGuide.domain.ai.weather.client.WeatherApiClient |
4 | | -import org.assertj.core.api.Assertions.assertThat |
5 | | -import org.junit.jupiter.api.Assumptions.assumeTrue |
| 4 | +import com.back.koreaTravelGuide.domain.ai.weather.dto.MidForecastDto |
| 5 | +import com.back.koreaTravelGuide.domain.ai.weather.dto.TemperatureAndLandForecastDto |
| 6 | +import com.back.koreaTravelGuide.domain.ai.weather.service.WeatherService |
6 | 7 | import org.junit.jupiter.api.DisplayName |
7 | 8 | import org.junit.jupiter.api.Test |
| 9 | +import org.mockito.Mockito.`when` |
8 | 10 | import org.springframework.beans.factory.annotation.Autowired |
9 | | -import org.springframework.beans.factory.annotation.Value |
| 11 | +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc |
10 | 12 | import org.springframework.boot.test.context.SpringBootTest |
11 | 13 | import org.springframework.context.annotation.Import |
| 14 | +import org.springframework.http.MediaType |
12 | 15 | import org.springframework.test.context.ActiveProfiles |
13 | | -import java.time.LocalDateTime |
14 | | -import java.time.format.DateTimeFormatter |
| 16 | +import org.springframework.test.context.bean.override.mockito.MockitoBean |
| 17 | +import org.springframework.test.web.servlet.MockMvc |
| 18 | +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get |
| 19 | +import org.springframework.test.web.servlet.result.MockMvcResultHandlers.print |
| 20 | +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath |
| 21 | +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status |
| 22 | +import org.springframework.transaction.annotation.Transactional |
15 | 23 |
|
16 | 24 | /** |
17 | 25 | * 실제 기상청 API 상태를 확인하기 위한 통합 테스트. |
18 | 26 | */ |
19 | 27 | @SpringBootTest(classes = [KoreaTravelGuideApplication::class]) |
| 28 | +@AutoConfigureMockMvc(addFilters = false) |
20 | 29 | @ActiveProfiles("test") |
21 | 30 | @Import(TestConfig::class) |
| 31 | +@Transactional |
22 | 32 | class WeatherApiClientTest { |
23 | 33 | @Autowired |
24 | | - private lateinit var weatherApiClient: WeatherApiClient |
25 | | - |
26 | | - @Value("\${weather.api.key}") |
27 | | - private lateinit var serviceKey: String |
| 34 | + private lateinit var mockMvc: MockMvc |
28 | 35 |
|
29 | | - private fun getCurrentBaseTime(): String { |
30 | | - val now = LocalDateTime.now() |
31 | | - val baseHour = if (now.hour >= 6) "0600" else "1800" |
32 | | - val date = if (now.hour >= 6) now else now.minusDays(1) |
33 | | - return date.format(DateTimeFormatter.ofPattern("yyyyMMdd")) + baseHour |
34 | | - } |
| 36 | + @MockitoBean |
| 37 | + private lateinit var weatherService: WeatherService |
35 | 38 |
|
36 | 39 | @DisplayName("fetchMidForecast - 실제 기상청 API 중기전망조회 (데이터 기대)") |
37 | 40 | @Test |
38 | 41 | fun fetchMidForecastTest() { |
39 | | - assumeTrue(serviceKey.isNotBlank() && !serviceKey.contains("WEATHER_API_KEY")) { |
40 | | - "API 키가 설정되지 않아 테스트를 건너뜁니다." |
41 | | - } |
42 | | - |
43 | | - val regionId = "11B00000" |
44 | | - val baseTime = getCurrentBaseTime() |
45 | | - |
46 | | - println("=== Test Parameters ===") |
47 | | - println("regionId: $regionId") |
48 | | - println("baseTime: $baseTime") |
49 | | - |
50 | | - val result = weatherApiClient.fetchMidForecast(regionId, baseTime) |
51 | | - println("=== Result ===") |
52 | | - println("result: $result") |
53 | | - |
54 | | - // 현재 API 응답이 null을 반환하는 것이 정상일 수 있으므로 테스트 통과 |
55 | | - // assertThat(result).isNotNull() |
| 42 | + val mockData = |
| 43 | + listOf( |
| 44 | + MidForecastDto( |
| 45 | + regionCode = "11B00000", |
| 46 | + baseTime = "2025101006", |
| 47 | + precipitation = "맑음", |
| 48 | + temperature = "평년과 비슷", |
| 49 | + maritime = null, |
| 50 | + variability = null, |
| 51 | + ), |
| 52 | + ) |
| 53 | + `when`(weatherService.getWeatherForecast()).thenReturn(mockData) |
| 54 | + |
| 55 | + // when & then - API 호출 및 검증 |
| 56 | + mockMvc.perform( |
| 57 | + get("/weather/test1") |
| 58 | + .contentType(MediaType.APPLICATION_JSON), |
| 59 | + ) |
| 60 | + .andExpect(status().isOk) |
| 61 | + .andExpect(jsonPath("$[0].regionCode").value("11B00000")) |
| 62 | + .andExpect(jsonPath("$[0].precipitation").value("맑음")) |
| 63 | + .andDo(print()) // 결과 출력 |
56 | 64 | } |
57 | 65 |
|
58 | | - @DisplayName("fetchTemperature - 실제 기상청 API 중기기온조회 (데이터 기대)") |
| 66 | + @DisplayName("TemperatureAndLandForecast - 실제 기상청 API 중기기온조회 + 중기육상예보조회(데이터 기대)") |
59 | 67 | @Test |
60 | 68 | fun fetchTemperatureTest() { |
61 | | - assumeTrue(serviceKey.isNotBlank() && !serviceKey.contains("WEATHER_API_KEY")) { |
62 | | - "API 키가 설정되지 않아 테스트를 건너뜁니다." |
63 | | - } |
64 | | - |
65 | | - val regionId = "11B10101" |
66 | | - val baseTime = getCurrentBaseTime() |
67 | | - |
68 | | - val result = weatherApiClient.fetchTemperature(regionId, baseTime) |
69 | | - println("=== Result ===") |
70 | | - println("result: $result") |
71 | | - |
72 | | - assertThat(result).isNotNull() |
73 | | - } |
74 | | - |
75 | | - @DisplayName("fetchLandForecast - 실제 기상청 API 중기육상예보조회 (데이터 기대)") |
76 | | - @Test |
77 | | - fun fetchLandForecastTest() { |
78 | | - assumeTrue(serviceKey.isNotBlank() && !serviceKey.contains("WEATHER_API_KEY")) { |
79 | | - "API 키가 설정되지 않아 테스트를 건너뜁니다." |
80 | | - } |
81 | | - |
82 | | - val regionId = "11B00000" |
83 | | - val baseTime = getCurrentBaseTime() |
84 | | - |
85 | | - val result = weatherApiClient.fetchLandForecast(regionId, baseTime) |
86 | | - println("=== Result ===") |
87 | | - println("result: $result") |
88 | | - |
89 | | - assertThat(result).isNotNull() |
| 69 | + // given |
| 70 | + val mockData = |
| 71 | + listOf( |
| 72 | + TemperatureAndLandForecastDto( |
| 73 | + regionCode = "11B10101", |
| 74 | + baseTime = "2025101006", |
| 75 | + minTemp = 10, |
| 76 | + maxTemp = 20, |
| 77 | + minTempRange = "8~12", |
| 78 | + maxTempRange = "18~22", |
| 79 | + amRainPercent = 30, |
| 80 | + pmRainPercent = 20, |
| 81 | + amWeather = "맑음", |
| 82 | + pmWeather = "구름많음", |
| 83 | + ), |
| 84 | + ) |
| 85 | + `when`(weatherService.getTemperatureAndLandForecast("11B10101")).thenReturn(mockData) |
| 86 | + |
| 87 | + // when & then |
| 88 | + mockMvc.perform(get("/weather/test2")) |
| 89 | + .andExpect(status().isOk) |
| 90 | + .andExpect(jsonPath("$[0].regionCode").value("11B10101")) |
| 91 | + .andExpect(jsonPath("$[0].minTemp").value(10)) |
| 92 | + .andDo(print()) |
90 | 93 | } |
91 | 94 | } |
0 commit comments