I'm trying use wiremock to simulate api result and test my endpoint. But unfortunately, I got response from exception "I/O error on GET request for "http://localhost:56994": Invalid response: 3".
- I'm setting
wiremock(it seems to work correctly (all logs working - start-stop)
@SpringBootTest
@AutoConfigureMockMvc
public class WeatherControllerTest {
@Autowired
MockMvc mockMvc;
@Autowired
ObjectMapper objectMapper;
@RegisterExtension
public static WireMockExtension wireMockServer = WireMockExtension.newInstance()
.options(wireMockConfig().dynamicPort())
.build();
@DynamicPropertySource
public static void propertyOverride(DynamicPropertyRegistry registry) {
registry.add("api.weather.cityNames", () -> "Jastarnia");
registry.add("api.weather.apiKey", () -> "123");
registry.add("api.weather.baseUrl", wireMockServer::baseUrl);
}
- Now I want to fake my API response by using wiremock
//given
FetchWeatherResponse fetchWeatherResponse = new FetchWeatherResponse(
"Jastarnia",
Arrays.asList(
new FetchWeatherResponse.WeatherData(20.5, 10.2, "2024-01-05"),
new FetchWeatherResponse.WeatherData(18.9, 8.6, "2024-01-06")
)
);
String json = objectMapper.writeValueAsString(fetchWeatherResponse);
wireMockServer.stubFor(WireMock.get(WireMock.urlPathEqualTo("/"))
.withQueryParam("city", WireMock.equalTo("Jastarnia"))
.withQueryParam("key", WireMock.equalTo("123"))
.willReturn(aResponse()
.withStatus(OK)
.withHeader("Content-Type", APPLICATION_JSON)
.withBody(json)));
I tried with that body or with
.withBody("""
{
"city_name": "Warsaw",
"data": [
{
"temp": 20.5,
"wind_spd": 10.2,
"datetime": "2024-01-05"
},
{
"temp": 18.9,
"wind_spd": 8.6,
"datetime": "2024-01-06"
}
]
}""".trim())));
- result is this same as above
Application works correctly but thats my impl
@Override
public List<FetchWeatherResponse> fetchWeather(List<String> urls) {
final HttpEntity<HttpHeaders> requestEntity = new HttpEntity<>(createHeader());
List<FetchWeatherResponse> fetchedWeathers = new LinkedList<>();
try {
for (String uri : urls) {
FetchWeatherResponse fetchedWeather = makeWeatherRequest(requestEntity, uri);
if(fetchedWeather == null) {
log.error("Response body was null.");
throw new ResponseStatusException(NO_CONTENT);
}
fetchedWeathers.add(fetchedWeather);
}
return fetchedWeathers;
} catch (ResourceAccessException e) {
log.error("Error while fetching locations: " + e.getMessage());
throw new ResponseStatusException(INTERNAL_SERVER_ERROR);
}
}
private FetchWeatherResponse makeWeatherRequest(HttpEntity<HttpHeaders> requestEntity, String url) {
ResponseEntity<FetchWeatherResponse> response = restTemplate.exchange(
url,
GET,
requestEntity,
new ParameterizedTypeReference<>() {
});
log.info("data downloaded successfully");
return response.getBody();
}
it throws throw new ResponseStatusException(INTERNAL_SERVER_ERROR);.
before log.info("data downloaded successfully");
so there is 100% error while fetching data.
thats my ResponseObject
@Data
@AllArgsConstructor
@NoArgsConstructor
public class FetchWeatherResponse {
@JsonProperty("city_name")
String cityName;
@JsonProperty("data")
List<WeatherData> data;
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class WeatherData {
@JsonProperty("temp")
double temperature;
@JsonProperty("wind_spd")
private double windSpd;
@JsonProperty("datetime")
private String datetime;
}
}
MvcResult response = mockMvc.perform(get("/api/best-weather?date=2024-01-05")
.contentType(APPLICATION_JSON_VALUE))
.andExpect(status().isOk())
.andReturn();
And thats my full logs of wiremock during request
p.b.w.domain.weather.WeatherServiceImpl : generated url http://localhost:57135?city=Jastarnia&key=123
2024-01-06T00:28:25.285+01:00 ERROR 16300 --- [ main] p.b.w.i.fetch.FetchWeatherImpl : Error while fetching locations: I/O error on GET request for "http://localhost:57135": Invalid response: 3
MockHttpServletRequest:
HTTP Method = GET
Request URI = /api/best-weather
Parameters = {date=[2024-01-05]}
Headers = [Content-Type:"application/json;charset=UTF-8"]
Body = null
Session Attrs = {}
Handler:
Type = pl.bartoszmech.weather.application.controller.WeatherController
Method = pl.bartoszmech.weather.application.controller.WeatherController#getWeather(String)
Async:
Async started = false
Async result = null
Resolved Exception:
Type = org.springframework.web.server.ResponseStatusException
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 503
Error message = null
Headers = [Content-Type:"application/json"]
Content type = application/json
Body = {"message":"500 INTERNAL_SERVER_ERROR"}
Forwarded URL = null
Redirected URL = null
Cookies = []
java.lang.AssertionError: Status expected:<200> but was:<503>
Expected :200
Actual :503
If you have question just ask.
I tried with different body responses, without queryParams (implementing it manually inside url)
Your returned status OK from response is from:
and it's hardcoded to 3, which is not valid http status code. Instead use for example
HttpStatus.OK.value(). Unfortunately rest template give you error message that is not very clear. When you change rest template for WebClient you would get error like this: org.springframework.web.reactive.function.client.WebClientRequestException: Status code '3' should be a three-digit positive integer.