mocking resttemplate exchange method returning null - spring-boot

I am trying to write the Junit test case for exchange method but it its returning null, can anybody tell me what is mistake I am doing here
My Actual Code is
HttpEntity httpEntity = cviBillingReportDateUtility.getHttpClient();
ResponseEntity<List<PersonDTO>> response = restTemplate.exchange(
personApiURI,
HttpMethod.GET,
httpEntity,
new ParameterizedTypeReference<List<PersonDTO>>() {
}
);
My Junit test code is like
when(restTemplate.exchange(any(String.class),
eq(HttpMethod.GET),
any(HttpEntity.class),
eq(new ParameterizedTypeReference<List<PersonDTO>>(){})
)).thenReturn(new ResponseEntity<List<PersonDTO>>(personList,HttpStatus.OK));

PowerMockito.when(restTemplate.exchange(ArgumentMatchers.anyString(), ArgumentMatchers.any(HttpMethod.class),
ArgumentMatchers.any(),
ArgumentMatchers.<ParameterizedTypeReference<List<cCustomerGroup>>>any()))
.thenReturn(responseEntity);
#You have to also mock endpoint url like below,
#Value("${url.customergroup}")
private String getCustomerGroups;
#Before
public void initialize() {
ReflectionTestUtils.setField(customerGroupService, "getCustomerGroups",
"http://localhost:8080/services/rest/customergroups");
}

Related

Mockito is returning "java.lang.IllegalArgumentException: URI is not absolute" in RestTemplate.exchange Springboot

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.
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?
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).
UPDATE:
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 (e.g. in a loop, etc.) try to inject a factory that creates the instances for you - so in the test you can mock the factory.

How to write Mockito for Rest template 2 based response from RestTemplate 1

#Test
public void getEventsByOrg() throws Exception {
String mockResposne = getXMLFromFile("classpath:OrgResponse.xml");
ResponseEntity<String> response = new ResponseEntity<>(mockResposne, HttpStatus.OK);
when(restTemplate.exchange(any(String.class), any(), any(HttpEntity.class), any(Class.class)))
.thenReturn(response);
ResponseEntity<List<OCVEvents>> ocvEvents = eventService.getEventsByGlobalKey(eventIdOrg, traceId);
verify(restTemplate).exchange(any(String.class), any(), captor.capture(), any(Class.class));
Events event = ocvEvents.getBody().get(0);
Events eventsPerson = new ObjectMapper().readValue(ResourceUtils.getFile("classpath:EventOrg.json"), Events.class);
assertThat(event.getHeader()).isEqualTo(eventsPerson.getHeader());
Now i have another Rest Call inside eventsService
How to write unit test for that
I need to hit a Rest API(1) & get the response, based on response i need to hit another Rest API (2)
i need to write the mockit0 for this class
If you have multiple rest api calls being made in your service class , you will have to mock all the api calls to return a mock data for your test to run. Just like you mocked the response for the first api call, add a mock response for the second api call before calling your service in you test. Instead of using any() as the argument matcher specify the particular url that you are going to be calling from the code to differentiate between the two api call mocks.
If you are on Springboot and using spring-boot-test for Integration testing , then you could use TestRestTemplate like:
TestRestTemplate testRestTemplate = new TestRestTemplate();
ResponseEntity<String> response = testRestTemplate.
getForEntity(FOO_RESOURCE_URL + "/1", String.class);
assertThat(response.getStatusCode(), equalTo(HttpStatus.OK));
or If you are just having a Unit test case using Mockito for instance then :
#Mock
private RestTemplate restTemplate;
#InjectMocks
private EventService eventService = new EventService();
#Test
public void givenMockingIsDoneByMockito_whenGetIsCalled_shouldReturnMockedObject() {
SomeObject instance = new SomeObject(“E001”, "Eric Simmons");
Mockito
.when(restTemplate.getForEntity(
“http://localhost:8080/test/E001”, SomeObject.class))
.thenReturn(new ResponseEntity(instance, HttpStatus.OK));
SomeObject returnedObject = eventService.getEventsByGlobalKey(id);
Assert.assertEquals(instance, returnedObject);
}

Provide generic class instead of a mapper class while executing an API using resttemplate

I'm trying to write an integration test for one of the API, but however it returns a XML object, where I don't have any corresponding class inorder to map. How can I do without any class?
Here is my code
HttpHeaders authHeaders = new HttpHeaders();
authHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
authHeaders.add("Authorization", "Bearer "+oAuthToken );
UriComponentsBuilder builder=UriComponentsBuilder.fromUriString(PES_END_POINT + PES_RESOURCE)
.queryParam("count", "100")
.queryParam("app-name", "bb")
HttpEntity entity = new HttpEntity(authHeaders);
Object response = restTemplate.exchange(builder.toUriString(), HttpMethod.POST, entity , Class<T> ); --> Here what generic class can I provide?
Any help would be greatly appreciated.
just use the ObjectMapper
ResponseEntity<String> response = restTemplate.exchange(builder.toUriString(), HttpMethod.POST, entity , String.class);
JavaType javaType = objectMapper.getTypeFactory().constructType(yourClass);
YourGenericClass<T> result = objectMapper.readValue(response.getBody(), javaType);

Unit testing Spring REST Controller

I have a Spring boot controller with a method like this:
// CREATE
#RequestMapping(method=RequestMethod.POST, value="/accounts")
public ResponseEntity<Account> createAccount(#RequestBody Account account,
#RequestHeader(value = "Authorization") String authorizationHeader,
UriComponentsBuilder uriBuilder) {
if (!account.getEmail().equalsIgnoreCase("")) {
account = accountService.createAccount(account);
HttpHeaders headers = new HttpHeaders();
System.out.println( "Account is null = " + (null == account)); //For debugging
headers.setLocation(uriBuilder.path("/accounts/{id}").buildAndExpand(account.getId()).toUri());
return new ResponseEntity<>(account, headers, HttpStatus.CREATED);
}
return new ResponseEntity<>(null, null, HttpStatus.BAD_REQUEST);
}
I'm trying to unit test it like this:
#Test
public void givenValidAccount_whenCreateAccount_thenSuccessed() throws Exception {
/// Arrange
AccountService accountService = mock(AccountService.class);
UriComponentsBuilder uriBuilder = mock(UriComponentsBuilder.class);
AccountController accountController = new AccountController(accountService);
Account account = new Account("someone#domain.com");
/// Act
ResponseEntity<?> createdAccount = accountController.createAccount(account, "", uriBuilder);
/// Assert
assertNotNull(createdAccount);
//assertEquals(HttpStatus.CREATED, createdAccount.getStatusCode());
}
but the account is always null. Any idea why is that ?
You may want to check my answer in How to test this method with spring boot test?
Not only you will find an answer to unit testing controllers but also how to include filters, handlers and interceptors in your test.
Hope this helps,
Jake
I think you need to when clause first of all.
when(accountController.createAccount(account, "", uriBuilder)).then(createAccount);
ResponseEntity<?> createdAccount = accountController.createAccount(account, "", uriBuilder);

Spring RestController handle Get Request with Body values

i currently develop an experimental prototype an wanted to ask if there is a way to accept a response body in a get request.
#RequestMapping(method=RequestMethod.GET, path="/stair/shippingorders", produces=MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity<?> getShippingOrder(#RequestBody JsonNode request) throws JsonProcessingException, IOException{
log.info("get body: " + request);
// do stuff
return ResponseEntity.ok(response);
}
the test should looks something like this
#Test
public void shouldAcceptRequestBodyinGetRequest() {
JSONObject body = new JSONObject();
body.appendField("stuff", "{}");
HttpEntity<JSONObject> entity = new HttpEntity<JSONObject>(body);
ResponseEntity<String> result = restTemplate.exchange(GET_URL,HttpMethod.GET, entity, String.class );
assertNotNull(result);
}
GET method doesn't support body, hence it won't be possible to send body as part of request. The common practice is to use POST instead

Resources