JUnit test for void method containing a RestTemplate exchange call - java

I am trying to write a Test class for one of my methods and I am new to JUnit. My class returns a void and has a RestTemplate.exchange call to an external endpoint.
I started off trying this, but this gives me a NullInsteadOfMockException.
#Test
public void service1test() throws IOException{
ResponseEntity<?> responseEntity = new ResponseEntity<>(HttpStatus.ACCEPTED);
RestTemplate restTemplate = Mockito.mock(RestTemplate.class);
Mockito.verify(restTemplate.exchange(Mockito.anyString(), Mockito.<HttpMethod> any(), Mockito.<HttpEntity<?>> any(), Mockito.<Class<?>> any(),
Mockito.<String, String> anyMap()));
}
Here's my method that I want to write unit test for.
#Autowired
private RestTemplate restTemplate;
public void service1(String a, String b) {
RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder();
this.restTemplate = restTemplateBuilder.build();
HttpHeaders headers = new HttpHeaders();
try {
headers.set("ID", ID);
headers.set("secret", secret);
System.out.println(docStoreUrl + itemID);
HttpEntity requestEntity = new HttpEntity<>(null, headers);
ResponseEntity response = restTemplate.exchange(url, HttpMethod.GET, requestEntity, Object.class);
log.info("Status code for get : {}", response.getStatusCodeValue());
if(response.getStatusCodeValue() == 200) {
Object document = (Object) response.getBody();
Class2.service2.execute(document);
}
else {
log.info("Failed to retrieve document due to {}", response.getStatusCodeValue());
}
}
I am new to JUnit testing and can't figure out how to write the Test class for this covering all the lines.
If this question is already answered, please point me to the appropriate URL.
Any help will be greatly appreciated.

Its a little bit late, but if anyone else falls over this:
This error will also occur, if you are using mockito wrong.
It should be:
Mockito.verify(restTemplate).exchange(Mockito.anyString() ...
Notice the closing bracket immediately after restTemplate, so exchange is called on top of mockito.

Related

How send request with query parameter "test[]=test" in spring?

I need to send get request to example.com/api with query param named test[]
For this i use spring rest tepmlate
UriComponentsBuilder builder = UriComponentsBuilder
.fromUriString(example.com/api)
.queryParam(test[], "test");
responseEntity = restTemplate.exchange(builder.toUriString(), HttpMethod.GET,
new HttpEntity<>(this.setHttpHeader()),
new ParameterizedTypeReference<List<MyDTO>>() {
});
But builder.toUriString() return example.com/api?test%5B%5D=test
I try to replace srting with my method
private String repairUri(String uri) {
return url.replaceAll("%5B%5D", "[]");
}
and call
responseEntity = restTemplate.exchange(repairUri(builder.toUriString()), HttpMethod.GET,
new HttpEntity<>(this.setHttpHeader()),
new ParameterizedTypeReference<List<MyDTO>>() {
});
But into restTemplate.exchange() this uri convert to example.com/api?test%5B%5D=test again.
Meanwhile i easy send example.com/api?test[]=test request by POSTMan and it's work.
How Can i send request to example.com/api?test[]=test in Spring?
I find one solution.
In my restTemplate bean definition I add this settings:
public RestTemplate myRestTemplate() {
RestTemplate restTemplate = restTemplate(timeout);
DefaultUriBuilderFactory builderFactory = new DefaultUriBuilderFactory();
builderFactory.setEncodingMode(DefaultUriBuilderFactory.EncodingMode.VALUES_ONLY);
restTemplate.setUriTemplateHandler(builderFactory);
restTemplate.setErrorHandler(new RestClientResponseExceptionHandler());
return restTemplate;
}
In this page some guys says that DefaultUriBuilderFactory.EncodingMode.NONE is also suitable.
Read more in link.
Just change your repairUri method to this when you call restTemplate.exchange to this :
responseEntity = restTemplate.exchange(URLDecoder.decode(builder.toUriString(), "UTF-8"), HttpMethod.GET,
new HttpEntity<>(this.setHttpHeader()),
new ParameterizedTypeReference<List<MyDTO>>() {
});

Call rest void method in controller using Spring Boot

i'm using Spring Boot for making Rest Controllers.
my controller is :
#RestController
public class VersionRestController {
#Autowired
VersionService versionService;
#GetMapping(value = "/csv", produces = "text/csv")
#ResponseStatus(value = HttpStatus.OK)
public void exportCsv(HttpServletResponse response) throws Exception {
String fileName = "allVersions.csv";
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"");
StatefulBeanToCsv<Version> writer = new StatefulBeanToCsvBuilder<Version>(response.getWriter())
.withQuotechar(CSVWriter.NO_QUOTE_CHARACTER).withSeparator(CSVWriter.DEFAULT_SEPARATOR)
.withOrderedResults(true).build();
writer.write(versionService.findAll());
}
}
im calling it like this
public void exportVersionAsCsv(){
final String uri = "http://localhost:8070/csv";
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<Version> response = restTemplate.getForEntity(uri, Version.class);
}
when i call the rest method direct in the browser it works fine, but when i call exportVersionAsCsv() in vaadin on click button it gives me org.springframework.web.client.HttpClientErrorException$NotAcceptable: 406 Not Acceptable
why is this happening ? any suggestion ?
thank you
Try this set setAccept to Media type to that is being produced by url you are consuming.
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
HttpEntity<String> entity = new HttpEntity<>("body", headers);
restTemplate.exchange(url, HttpMethod.POST, entity, String.class);

How to test restclient using RestTemplate and JUnit?

I am new to JUNIT and using RestTemplate to call my service, I'm getting 200 response for the same. But, I can't test the class using JUnit. Tried different approaches and getting 400 and 404. I want to post the request body (json) and test the status. Please let me know if there is any issue.
/**
* Rest client implementation
**/
public class CreateEmailDelegate implements CDM {
#Autowired
private RestTemplate restTemplate;
private String url = "http://example.com/communications/emails";
public ResponseEntity<CDResponse> createEmail(CDMEmailRequest cDRequest) throws UnavailableServiceException, InvalidInputException {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("SR_API_Key", SR_API_KEY);
httpHeaders.set("consumerIdentification", CONSUMER_IDENTIFICATION);
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
HttpEntity< CDMEmailRequest > cDRequestEntity = new HttpEntity<>( cDRequest, httpHeaders);
ResponseEntity< CDResponse > cDResponse = null;
try {
cDResponse = restTemplate.postForEntity(url, cDRequestEntity, CDResponse.class);
} catch (Exception e) {
LOGGER.error(e.getMessage());
throw e;
}
return cDResponse;
}
}
My Test class which return 404 status instead of 200
#RunWith(SpringJUnit4ClassRunner.class)
public class CreateEmailCommunicationDelegateTest {
#Before
public void setup() {
httpHeaders = new HttpHeaders();
httpHeaders.set("SR_API_Key", SR_API_KEY);
httpHeaders.set("consumerIdentification", CONSUMER_IDENTIFICATION);
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
DefaultMockMvcBuilder builder = MockMvcBuilders.webAppContextSetup(this.wac);
this.mockMvc = builder.build();
}
public void testResponse() throws Exception, HttpClientErrorException, JsonProcessingException {
String url = "http://example.com/CommunicationDeliveryManagement-Service-1.0.0/communications/emails";
CDMEmailRequest anObject = new CDMEmailRequest();
ResultMatcher ok = MockMvcResultMatchers.status().isOk();
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, false);
ObjectWriter ow = mapper.writer().withDefaultPrettyPrinter();
String requestJson = ow.writeValueAsString(anObject);
System.out.println(requestJson);
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.post(url).contentType(MediaType.APPLICATION_JSON_UTF8).content(requestJson);
this.mockMvc.perform(builder).andExpect(ok).andDo(MockMvcResultHandlers.print());
}
}
My Test class using TestRestTemplate instead MockMvc returns 400
#RunWith(SpringJUnit4ClassRunner.class)
public class CreateEmailCommunicationDelegateTest {
#Before
public void setup() {
httpHeaders = new HttpHeaders();
// rest headers as above
}
#Test
public void testResponse() throws Exception, HttpClientErrorException, JsonProcessingException {
String url = "http://example.com/CommunicationDeliveryManagement-Service-1.0.0/communications/emails";
String username = "";
String password = "";
HttpEntity<CDMEmailRequest>
cDEntity = new HttpEntity<>(httpHeaders);
restTemplate = new TestRestTemplate(username, password);
responseEntity =
restTemplate.exchange(url, HttpMethod.POST, cDEntity,
CDResponse.class);
assertNotNull(responseEntity);
assertEquals(HttpStatus.OK,
responseEntity.getStatusCode());
}
}
I think you're trying to implement an integration test instead of an unit test, there is quite difference. MockMvc should be used to implement unit tests and TestRestTemplate for integration tests. You can't neither use it for testing a Client implementation.
See Unit and Integration Tests in Spring Boot
If you are working with Spring Boot you could achieve your goal using another approach see this question Spring boot testing of a rest client using #RestClientTest.

How to make a rest api call in java and map the response object?

I'm currently developing my first java program who'll make a call to a rest api(jira rest api, to be more especific).
So, if i go to my browser and type the url =
"http://my-jira-domain/rest/api/latest/search?jql=assignee=currentuser()&fields=worklog"
I get a response(json) with all the worklogs of the current user.
But my problem is, how i do my java program to do this ?
Like,connect to this url, get the response and store it in a object ?
I use spring, with someone know how to this with it.
Thx in advance guys.
Im adding, my code here:
RestTemplate restTemplate = new RestTemplate();
String url;
url = http://my-jira-domain/rest/api/latest/search/jql=assignee=currentuser()&fields=worklog
jiraResponse = restTemplate.getForObject(url,JiraWorklogResponse.class);
JiraWorkLogResponse is a simple class with some attributes only.
Edit,
My entire class:
#Controller
#RequestMapping("/jira/worklogs")
public class JiraWorkLog {
private static final Logger logger = Logger.getLogger(JiraWorkLog.class.getName() );
#RequestMapping(path = "/get", method = RequestMethod.GET, produces = "application/json")
public ResponseEntity getWorkLog() {
RestTemplate restTemplate = new RestTemplate();
String url;
JiraProperties jiraProperties = null;
url = "http://my-jira-domain/rest/api/latest/search?jql=assignee=currentuser()&fields=worklog";
ResponseEntity<JiraWorklogResponse> jiraResponse;
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders = this.createHeaders();
try {
jiraResponse = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<Object>(httpHeaders),JiraWorklogResponse.class);
}catch (Exception e){
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
}
return ResponseEntity.status(HttpStatus.OK).body(jiraResponse);
}
private HttpHeaders createHeaders(){
HttpHeaders headers = new HttpHeaders(){
{
set("Authorization", "Basic something");
}
};
return headers;
}
This code is returning :
org.springframework.http.converter.HttpMessageNotWritableException
Anyone knows why ?
All you need is http client. It could be for example RestTemplate (related to spring, easy client) or more advanced and a little more readable for me Retrofit (or your favorite client).
With this client you can execute requests like this to obtain JSON:
RestTemplate coolRestTemplate = new RestTemplate();
String url = "http://host/user/";
ResponseEntity<String> response
= restTemplate.getForEntity(userResourceUrl + "/userId", String.class);
Generally recommened way to map beetwen JSON and objects/collections in Java is Jackson/Gson libraries. Instead them for quickly check you can:
Define POJO object:
public class User implements Serializable {
private String name;
private String surname;
// standard getters and setters
}
Use getForObject() method of RestTemplate.
User user = restTemplate.getForObject(userResourceUrl + "/userId", User.class);
To get basic knowledge about working with RestTemplate and Jackson , I recommend you, really great articles from baeldung:
http://www.baeldung.com/rest-template
http://www.baeldung.com/jackson-object-mapper-tutorial
Since you are using Spring you can take a look at RestTemplate of spring-web project.
A simple rest call using the RestTemplate can be:
RestTemplate restTemplate = new RestTemplate();
String fooResourceUrl = "http://localhost:8080/spring-rest/foos";
ResponseEntity<String> response = restTemplate.getForEntity(fooResourceUrl + "/1", String.class);
assertThat(response.getStatusCode(), equalTo(HttpStatus.OK));
The issue could be because of the serialization. Define a proper Model with fields coming to the response. That should solve your problem.
May not be a better option for a newbie, but I felt spring-cloud-feign has helped me to keep the code clean.
Basically, you will be having an interface for invoking the JIRA api.
#FeignClient("http://my-jira-domain/")
public interface JiraClient {
#RequestMapping(value = "rest/api/latest/search?jql=assignee=currentuser()&fields=", method = GET)
JiraWorklogResponse search();
}
And in your controller, you just have to inject the JiraClient and invoke the method
jiraClient.search();
And it also provides easy way to pass the headers.
i'm back and with a solution (:
#Controller
#RequestMapping("/jira/worklogs")
public class JiraWorkLog {
private static final Logger logger = Logger.getLogger(JiraWorkLog.class.getName() );
#RequestMapping(path = "/get", method = RequestMethod.GET, produces = "application/json")
public ResponseEntity<JiraWorklogIssue> getWorkLog(#RequestParam(name = "username") String username) {
String theUrl = "http://my-jira-domain/rest/api/latest/search?jql=assignee="+username+"&fields=worklog";
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<JiraWorklogIssue> response = null;
try {
HttpHeaders headers = createHttpHeaders();
HttpEntity<String> entity = new HttpEntity<>("parameters", headers);
response = restTemplate.exchange(theUrl, HttpMethod.GET, entity, JiraWorklogIssue.class);
System.out.println("Result - status ("+ response.getStatusCode() + ") has body: " + response.hasBody());
}
catch (Exception eek) {
System.out.println("** Exception: "+ eek.getMessage());
}
return response;
}
private HttpHeaders createHttpHeaders()
{
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.add("Authorization", "Basic encoded64 username:password");
return headers;
}
}
The code above works, but can someone explain to me these two lines ?
HttpEntity<String> entity = new HttpEntity<>("parameters", headers);
response = restTemplate.exchange(theUrl, HttpMethod.GET, entity, JiraWorklogIssue.class);
And, this is a good code ?
thx (:

Content type 'null' not supported returned by Spring RESTTemplate getForObject method

I have a simple REST method in a Spring MVC controller as follows which has a signature of:
#RequestMapping(value="/person/{personId}", method=RequestMethod.GET)
public #ResponseBody Object getPerson(#PathVariable("personId") String personId) {
...
}
The output is type Object because several different data types are returned from this method.
When called from a test program within the Spring MVC application, as follows:
private static void getPerson() {
logger.info(Rest.class.getName() + ".getPerson() method called.");
RestTemplate restTemplate = new RestTemplate();
Person person = restTemplate.getForObject("http://localhost:8080/Library/rest/person/1", Person.class);
ObjectMapper responseMapper = new ObjectMapper();
...
}
The response is Content type 'null' not supported and the call fails.
Can anyone advise why?
When called from a test program in another application which doesn't use Spring but which makes HTTP GET requests, the controller method is called properly and works.
You can try this:
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setReadTimeout(VERSION_CHECK_READ_TIMEOUT);
RestTemplate template = new RestTemplate(requestFactory);
Person person = restTemplate.getForObject("http://localhost:8080/Library/rest/person/1", Person.class);
If above doesn't work you can try using a Entity approach like:
RestTemplate restTemplate = new RestTemplate();
// Prepare acceptable media type
List<MediaType> acceptableMediaTypes = new ArrayList<MediaType>();
acceptableMediaTypes.add(MediaType.APPLICATION_XML); // Set what you need
// Prepare header
HttpHeaders headers = new HttpHeaders();
headers.setAccept(acceptableMediaTypes);
HttpEntity<Person> entity = new HttpEntity<Person>(headers);
// Send the request as GET
try {
ResponseEntity<PersonList> result = restTemplate.exchange("http://localhost:8080/Library/rest/person/1", HttpMethod.GET, entity, PersonList.class);
// Add to model
model.addAttribute("persons", result.getBody().getData());
} catch (Exception e) {
logger.error(e);
}
There are many useful examples here.
Hope to help

Categories