Mockito is returning "java.lang.IllegalArgumentException: URI is not absolute" in RestTemplate.exchange. I am not sure why this is happening because it seems I am mocking the restTemplate properly and since I am seeing that exception, it seems that RestTemplate is not a mock.
Here is my class
@Component
public class RestTemplateWrapper {
private static final Logger LOGGER = LoggerFactory.getLogger(RestTemplateWrapper.class);
public <T> ResponseEntity<T> callWebServiceGET(String url,HttpEntity<?> httpEntity,
ParameterizedTypeReference<T> parameterizedTypeReference) {
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<T> response=null;
LOGGER.trace("Entered callWebServiceGET");
LOGGER.info("Calling WebService {}", url);
try {
response=restTemplate.exchange(url, HttpMethod.GET, httpEntity, parameterizedTypeReference);
} catch (HttpClientErrorException e) {
if (HttpStatus.NOT_FOUND.equals(e.getStatusCode())) {
LOGGER.error("Service Unavailable - Code 404 returned. " + url + e.getMessage());
} else if (HttpStatus.UNAUTHORIZED.equals(e.getStatusCode())) {
LOGGER.error("Token Expired- Code 401 returned. " + e.getMessage());
} else if (HttpStatus.BAD_REQUEST.equals(e.getStatusCode())) {
LOGGER.error("Bad Input, 400 returned.{} {} ", url , e.getMessage(), e);
} else {
LOGGER.error("WEB Service Failure. " + e.getMessage());
}
}
return response;
}
}
And here is my TestCase:
@PrepareForTest({RestTemplateWrapper.class})
public class RestTemplateWrapperTest {
@Mock
private RestTemplate mockRestTemplate;
@InjectMocks
private RestTemplateWrapper webUtils;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
@Test
public void callWebServiceGET_OK() {
HttpEntity<String> httpEntity= new ResponseEntity<>(HttpStatus.OK);
ResponseEntity<String> entityResponse=new ResponseEntity<>("MOCK_RESPONSE", HttpStatus.OK);
when(mockRestTemplate.exchange(eq("/objects/get-objectA"), eq(HttpMethod.GET), eq(httpEntity),any(
ParameterizedTypeReference.class))).thenReturn(
entityResponse);
ResponseEntity<String> mockResponse= webUtils.callWebServiceGET("",null, new ParameterizedTypeReference<String>(){
});
//verify(mockRestTemplate,times(1)).exchange(Matchers.anyString(), Matchers.any(), Matchers.any());
Assert.assertEquals("MOCK_RESPONSE",mockResponse.getBody());
}
}
The response:
URI is not absolute
java.lang.IllegalArgumentException: URI is not absolute
at java.net.URI.toURL(URI.java:1088)
at org.springframework.http.client.SimpleClientHttpRequestFactory.createRequest(SimpleClientHttpRequestFactory.java:145)
at org.springframework.http.client.support.HttpAccessor.createRequest(HttpAccessor.java:87)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:727)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:666)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:604)
at com.project.di.tp.purchaseorderservice.utils.RestTemplateWrapper.callWebServiceGET(RestTemplateWrapper.java:29)
at com.project.di.tp.purchaseorderservice.utils.RestTemplateWrapperTest.callWebServiceGET_OK(RestTemplateWrapperTest.java:51)
Any idea about how to solve this issue? I have been trying like 4 hours.
Although it is not stated explicitly in the JavaDocs it is the case that you have to provide an absolute URL there.
This is because you do nowhere provide a base URL where a relative URL would be relative to. You could not enter "/objects/get-objectA"
as URL in your browser either.
So I would suggest that you use something like "http://example.com/objects/get-objectA"
instead for the first parameter:
when(mockRestTemplate.exchange(
eq("http://example.com/bla"),
eq(HttpMethod.GET),
isNull(HttpEntity.class),
any(ParameterizedTypeReference.class))).
thenReturn(entityResponse);
ResponseEntity<String> mockResponse =
webUtils.callWebServiceGET(
"http://example.com/bla",
null,
new ParameterizedTypeReference<String>(){});
Please note that the call to webUtils.callWebServiceGET
with given parameters would not make Mockito return the wanted answer, so I changed for one the URL in the call to the absolute URL you are expecting in the Mockito.when
and also changed the parameter expected there to be a typed null
(typed to match the method signature).
As you found out by yourself already, your Mockito.when
doesn't work because you do not use the created mock from the test in your tested method, but instead create a fresh instance of RestTemplate
in each call of callWebServiceGET
. (Don't know why I didn't see it earlier, sorry!)
I recommend that instead you inject the RestTemplate
into the tested class with a constructor:
private final RestTemplate restTemplate;
public RestTemplateWrapper(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
// remove the following line in the method callWebServiceGET:
// RestTemplate restTemplate = new RestTemplate();
With this code, Spring will automatically inject your mocked RestTemplate
into the test, but for running the production code you need to add a bean to provide a RestTemplate
for injection.
Add this to a Configuration class where you also define other beans:
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
// Do any additional configuration here
return builder.build();
}
(Found this code snippet in an answer to How to autowire RestTemplate using annotations )
And as a general advice for testing: try to avoid the use of the new
operator in any code you want to test, but use injection instead. If you need to create multiple instances (eg in a loop, etc.) try to inject a factory that creates the instances for you - so in the test you can mock the factory.
I found the solution, it seems the problem is that my class is RestTemplateWrapper is creating a instance inside callWebServiceGET therefore mockito can`t mock that object. If if set the object outside the method, it works but I dont want to do that.
Is there any way to mock a object that is inside a method?
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.