Java code for api call
I want to know how to test the below two lines of code.
private void api(){
//Code to call an API and i want to test this in groovy spock
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setAccept(Arrays.asList(MediaType.APPLICATION_JSON);
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
RestTemplate restTemplate = new RestTemplate();
String url ="url";
String body ="body";
//How to mock below line
RequestEntity<String> requestEntity = RequestEntity.put(new URI(url)).contentType(MediaType.APPLICATION_JSON).body(body);
//And this line
ResponseEntity<String> responseEntity = restTemplate.exchange(requestEntity,String.class);
HttpStatus StatusCode = responseEntity.getStatusCode();
}
This is not a Spock question as such (you didn't present a single line of Spock specification, so nobody knows what you have tried so far), rather a software engineering or general testing question. The problem with testing spaghetti code - and here I mean code which both does something and creates lots of objects at the same time - is that from the outside there is no access to objects created inside a method and stored in a local variable. There are two ways to refactor your code for better testability:
If it makes sense, change the code so as to enable the user to inject the dependencies from the outside instead of the code creating them internally. Please google "dependency injection" and find variants like
Another way is to factor out the object-creating parts of the method into smaller producer (or creator or factory) methods which then you can overwrite (stub) according to your choice in your test when using a partial mock (spy) object. Spock provides such spies, so you can easily use them.
I am going to show the latter approach for your information:
package de.scrum_master.stackoverflow.q58101434;
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
public class MyRestApi {
public HttpStatus api() throws URISyntaxException {
//Code to call an API and i want to test this in groovy spock
HttpHeaders httpHeaders = createHttpHeaders();
RestTemplate restTemplate = createRestTemplate();
String url ="url";
String body ="body";
//How to mock below line
RequestEntity<String> requestEntity = createRequestEntity(url, body);
//And this line
ResponseEntity<String> responseEntity = executeRequest(restTemplate, requestEntity);
return responseEntity.getStatusCode();
}
HttpHeaders createHttpHeaders() {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
return httpHeaders;
}
RestTemplate createRestTemplate() {
return new RestTemplate();
}
RequestEntity<String> createRequestEntity(String url, String body) throws URISyntaxException {
return RequestEntity.put(new URI(url)).contentType(MediaType.APPLICATION_JSON).body(body);
}
ResponseEntity<String> executeRequest(RestTemplate restTemplate, RequestEntity<String> requestEntity) {
return restTemplate.exchange(requestEntity,String.class);
}
}
See how the method is more structured and more readable now (could still be improved, I just did it in a quick & dirty way)? Please especially notice the helper methods createRequestEntity
and executeRequest
.
Now here is how you can write your Spock test:
package de.scrum_master.stackoverflow.q58101434
import org.springframework.http.HttpStatus
import org.springframework.http.RequestEntity
import org.springframework.http.ResponseEntity
import spock.lang.Specification
import spock.lang.Unroll
class MyRestApiTest extends Specification {
@Unroll
def "API returns status code #statusCode"() {
given: "prepare mocks + spy"
RequestEntity<String> requestEntity = Mock()
ResponseEntity<String> responseEntity = Mock() {
getStatusCode() >> httpStatus
}
MyRestApi myRestApi = Spy() {
createRequestEntity(_, _) >> requestEntity
executeRequest(_, _) >> responseEntity
}
when: "execute API method"
def result = myRestApi.api()
then: "check expected results"
// This actually only tests mockfunctionality, your real test would look differently
statusCode == result.value()
reasonPhrase == result.reasonPhrase
where:
httpStatus | statusCode | reasonPhrase
HttpStatus.OK | 200 | "OK"
HttpStatus.MOVED_PERMANENTLY | 301 | "Moved Permanently"
HttpStatus.UNAUTHORIZED | 401 | "Unauthorized"
}
}
Feel free to ask (related!) follow-up questions if you do not understand this code. I advise you to learn more about clean code, testability, mock testing in general and also about Spock in particular.