Testing Okhttp3 response body - java.lang.IllegalStateException: request == null - java

I have a method in class which does a HTTP GET call to get the response object and utilize this object further. The pesudo code is below:
public class ABC{
public method abc1(){
HttpUrl url = HttpUrl.parse("url").newBuilder()
.addPathSegment("path1")
.build();
Request request = new Request.Builder().url(url).build();
try (Response response = client.newCall(request).execute()) {
ResponseBody responseBody = response.body();
String body = responseBody.string();
//other logic
}catch (IOException e) {}
}
}
Now I am writing a unit test to test with different values in the response object (json object). This is as below:
public class ABCTest{
#Mock
private OkHttpClient mockHttpClient;
#Mock
private Call mockCall;
#Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
}
#Test
public void abc1Test(){
ResponseObjectInJson responseObjectInJson = new ResponseObjectInJson(); //this is a object from my POJO class that i create in order to be received as a response
JSONObject jsonObject = new
JSONObject(responseObjectInJson);
ResponseBody body =
ResponseBody.create(MediaType.parse("application/json"),new
Gson().toJson(jsonObject));
Response.Builder builder = new Response.Builder();
builder.code(200);
Response response = builder.body(body).build();
when(mockCall.execute()).thenReturn(response);
when(mockHttpClient.newCall(any(Request.class))).thenReturn(mockCall);
//call the abc1() method here to see the response and behaviour
}
}
The problem is, when i debug, it throws InvocationTargetException when building the response builder.body(body).build();
And shows java.lang.IllegalStateException: request == null. I understand that i need to set request in the Response.Builder because when i evaluate the expression builder.body(body) in debugger, in the result it shows headers and body, but request is null.
i.e., builder.request(//a request here)
My question is:
1. In response why the request is needed?
2. How to set this? because i am unable to mock since its final.
Thanks in advance

Related

Handling of various exception cases in rest template call

I am making rest template call to get the data from other microservice for this I am using the exchange method. This I am doing when a particular function gets called and below is the sample code for the same.
#Service
public void findUserById()
{
String username = "chathuranga";
String password = "123";
Integer userId = 1;
String url = "http://localhost:8080/users/" + userId;
//setting up the HTTP Basic Authentication header value
String authorizationHeader = "Basic " + DatatypeConverter.printBase64Binary((username + ":" + password).getBytes());
HttpHeaders requestHeaders = new HttpHeaders();
//set up HTTP Basic Authentication Header
requestHeaders.add("Authorization", authorizationHeader);
requestHeaders.add("Accept", MediaType.APPLICATION_JSON_VALUE);
//request entity is created with request headers
HttpEntity<AddUserRequest> requestEntity = new HttpEntity<>(requestHeaders);
ResponseEntity<FindUserResponse> responseEntity = restTemplate.exchange(
url,
HttpMethod.GET,
requestEntity,
FindUserResponse.class
);
// if (responseEntity.getStatusCode() == HttpStatus.OK) {
// System.out.println("response received");
System.out.println(responseEntity.getBody());
//} else {
// System.out.println("error occurred");
// System.out.println(responseEntity.getStatusCode());
//}
}
To handle the various exceptions code for example 500, 404 I want to made resttemplate builder class, (not the commented code) Which must be coded in different class for this I am referring this (custom hadler part)
I am not using try catch as it is not good approach when multiple calls happen in production environment.
I am also getting resource access exception while using exchange function which also needs to handle.
Now I am not getting how this class of custom handler should be called for handling response like 500.
If someone can help me with the sample code that would be very helpfull as I cannot test my code because it is not deployed for testing purpose till now
here is a sample
#ControllerAdvice
public class ErrorHandler {
#ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
#ExceptionHandler(ResourceAccessException.class)
public #ResponseBody
String handleResourceAccessException(
ResourceAccessException ex) {
return "internal server error";
}
}
When you use #ControllerAdvice , it will catch the exception you mention in #ExceptionHandler and here you can handle it the way you want.
If you don't want to return the response to the client right away, (for example, ignore ResourceAccessException and continue), you can override the handleError method of DefaultResponseErrorHandler, which is used by RestTemplate to handle the non 2xx codes.
public class ErrorHandler extends DefaultResponseErrorHandler {
#Override
public void handleError(ClientHttpResponse response, HttpStatus statusCode) {
// write your code here
}
}

Testing REST Api mock http server

I would like to test an application that connects to Github api, download some records and do something with them.
I want to have a mock object and I did something like that:
#SpringBootTest
public class GithubApiTest
{
GithubApiClient githubApiClient;
#Mock
HttpClient httpClient;
HttpRequest httpRequest;
#Value("response.json")
private String response;
#BeforeTestClass
void init() throws IOException, InterruptedException {
HttpRequest request = HttpRequest.newBuilder()
.GET()
.uri(URI.create("https://api.github.com/repos/owner/reponame"))
.build();
githubApiClient = new GithubApiClient(httpClient);
Mockito.when(httpClient.send(request, HttpResponse.BodyHandlers.ofString())).thenReturn(<here>
);
githubApiClient = new GithubApiClient(httpClient);
}
}
Looks it good? What should I put into thenReturn (it needs a HttpResponse but I dont know how to create this). Thanks for your answers. If you have any better ideas I will be grateful.
Update:
String response is a example reponse
You create a mocked response of type HttpResponse.
The mockedResponse will have status code 200, and the response body is "ExampleOfAResponseBody" which is of type String which you requested.
import java.net.http.HttpResponse;
HttpResponse<String> mockedResponse = Mockito.mock(HttpResponse.class);
Mockito.when(mockedResponse.statusCode()).thenReturn(200);
Mockito.when(mockedResponse.body()).thenReturn("ExampleOfAResponseBody");
Mockito.when(httpClient.send(request, HttpResponse.BodyHandlers.ofString())).thenReturn(mockedResponse);

Testing Unirest with PowerMockito

I want to test a method that sends a get request to a server using Unirest
I have used PowerMockito and Mockito to test some methods, but when I try to do it on the method below, I get null pointer exception.
This is the method I want to test:
public HttpResponse<JsonNode> jsonRequest(String path) {
HttpResponse<JsonNode> jsonResponse = null;
try {
jsonResponse = Unirest
.get(path)
.header("accept", "application/json")
.asJson();
} catch (UnirestException e) {
System.out.println("Server is unreachable at the moment. Please try again later");
}
return jsonResponse;
}
And this is the test case:
#RunWith(PowerMockRunner.class)
#PrepareForTest(Unirest.class)
public class TestModel {
#Mock
private GetRequest getRequest;
#Mock
private HttpResponse<JsonNode> httpResponse;
#InjectMocks
DatabaseModel databaseModel;
#Test
public void testController() {
PowerMockito.mockStatic(Unirest.class);
JsonNode jsonNode = mock(JsonNode.class);
when(Unirest.get("12345")).thenReturn(getRequest);
when(getRequest.asJson()).thenReturn(httpResponse);
when(httpResponse.getStatus()).thenReturn(200);
assertEquals(200, databaseModel.jsonRequest("12345").getStatus());
}
So I expect to get 200 (Or any status\body I will decide on)
But for some reason I get java.lang.NullPointerException
which directs me to this line:
.asJson();
in the getRequest.
Thanks in advance
You were almost there, you forgot to set-up the header:
when(Unirest.get("12345")).thenReturn(getRequest);
when(getRequest.header("accept", "application/json").thenReturn(getRequest)
when(getRequest.asJson()).thenReturn(httpResponse);
when(httpResponse.getStatus()).thenReturn(200);

set ClientRequestContext property dynamically in ClientRequestFilter

hey everyone i just want to know how can we set a property on ClientRequestContext object to a dynamic value when using ClientRequestFilter in jax-rs web service. just like this
Suppose i have an object
MyObject obj=new MyObject();
obj.nmae="simon";
obj.vendor=209;
Now i want to call a web service for which i create a jersey client and for that client i created the filter.Now what i want to know how to get my object passed down to clientFilter so i can set ClientRequestContext property to myObject?
#Provider
public class RequestClientFilter implements ClientRequestFilter {
#Override
public void filter(ClientRequestContext requestContext) throws IOException {
// how to set this to a variable value passed from a function in my code
requestContext.setProperty("test", "test client request filter");
//something along these lines
requestContext.setProperty("myobj",obj);
}
}
this is what is happening
MyObject obj=new MyObject();
obj.nmae="simon";
obj.vendor=209;
ClientConfig config = new ClientConfig();
config.register(EntityLoggingFilter.class);
config.register(GsonMessageBodyHandler.class);
config.register(ClFilter.class);
// config.property(ClientProperties.CONNECT_TIMEOUT, 1000);
config.property(ClientProperties.READ_TIMEOUT, 10000);
try {
Client client = ClientBuilder.newClient(config);
WebTarget webTarget = client.target("http://localhost:8081/ServicB").path("Register")
.path("Service");
System.out.println(webTarget.getUri());
Invocation.Builder invocationBuilder = webTarget.request().accept(MediaType.APPLICATION_JSON);
Response response = invocationBuilder.post(Entity.json("anything"));
System.out.println(response.getStatus());
String bresponse = response.readEntity(String.class);
if (bresponse == null) {
System.out.println("null response");
}
System.out.println(bresponse);
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
You can register the filter as a class or an instance. If MyObject is just a one time object, you can simply pass the object through the constructor of the filter and then register it.
config.register(new RequestClientFilter(myObject));
If MyObject will change for each request, then you can also register the filter with the WebTarget instead. So with each different request, you can use a different object.
Response response1 = client.target(uri)
.register(new RequestClientFilter(myObjectOne))
.request()
.get();
Response response2 = client.target(uri)
.register(new RequestClientFilter(myObjectTwo))
.request()
.get();

Response object along with http status code

I want to return http status code along with response object. If i just return response object in failure scenario the status is getting returned as 200. But i want to send the status that is returned by the service (eg: 403) along with the response object. But below piece of code is just returning message along with the status. I want response object in this case orderdetails object which has failure reasons and other fields. any help how to pass object back to client?
#Component
public class OrderController {
#Autowired
private OrderService service;
public OrderDetails createOrder(final OrderDetails orderVO) {
try {
OrderDetails orderVO = service.createOrder() // service call
} catch(OrderException e) {
OrderDetails orderVO = e.getOrderDetails(); // even in exception cases backend liberary sends same object with error messages
ServiceException exception = new ServiceException(e.getStatus(), e.getMessage());
exception.setOrderDetails(orderVO);
throw exception;
}
return orderVO;
}
}
You could define a #ControllerAdvice and add your error handling logic there.
#ControllerAdvice
public class SampleControllerAdvice {
#ExceptionHandler(ServiceException.class)
public ResponseEntity<YourResponse> handleServiceException(ServiceException e) {
// YourResponse could be any serializable type (including ServiceException)
YourResponse body = ...
// Set the desired HTTP response headers
HttpHeaders responseHeaders = ...
// Set the desired HTTP response status
HttpStatus status = ...
return new ResponseEntity<YourResponse>(body, headers, status);
}
}
If ServiceException gets throws the handler method is invoked.
Probably the OrderDetails in the OrderException is null...
So with exception.setOrderDetails(orderVO); you put null in the Exception!!!

Categories

Resources