Skip to content

Commit de4cb70

Browse files
JIWONKIMSclaude
andauthored
test: Refactor WeatherApiClientTest to use MockMvc with mocked service (#114)
- Change from integration test to controller test using MockMvc - Add @MockitoBean for WeatherService to avoid real API calls - Add @AutoConfigureMockMvc(addFilters = false) to bypass security filters - Mock test data for MidForecastDto and TemperatureAndLandForecastDto - Update imports to use MockMvc request builders and matchers This improves test speed and reliability by removing external API dependencies. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <[email protected]>
1 parent 194751c commit de4cb70

File tree

1 file changed

+66
-63
lines changed

1 file changed

+66
-63
lines changed
Lines changed: 66 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,94 @@
1+
12
import com.back.koreaTravelGuide.KoreaTravelGuideApplication
23
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
67
import org.junit.jupiter.api.DisplayName
78
import org.junit.jupiter.api.Test
9+
import org.mockito.Mockito.`when`
810
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
1012
import org.springframework.boot.test.context.SpringBootTest
1113
import org.springframework.context.annotation.Import
14+
import org.springframework.http.MediaType
1215
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
1523

1624
/**
1725
* 실제 기상청 API 상태를 확인하기 위한 통합 테스트.
1826
*/
1927
@SpringBootTest(classes = [KoreaTravelGuideApplication::class])
28+
@AutoConfigureMockMvc(addFilters = false)
2029
@ActiveProfiles("test")
2130
@Import(TestConfig::class)
31+
@Transactional
2232
class WeatherApiClientTest {
2333
@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
2835

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
3538

3639
@DisplayName("fetchMidForecast - 실제 기상청 API 중기전망조회 (데이터 기대)")
3740
@Test
3841
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()) // 결과 출력
5664
}
5765

58-
@DisplayName("fetchTemperature - 실제 기상청 API 중기기온조회 (데이터 기대)")
66+
@DisplayName("TemperatureAndLandForecast - 실제 기상청 API 중기기온조회 + 중기육상예보조회(데이터 기대)")
5967
@Test
6068
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())
9093
}
9194
}

0 commit comments

Comments
 (0)