I have a problem running Junit Service in my spring-boot
microservice. I defined bearer token getting from /authenticate/login. It is valid. I can send a request to any service through Postman.
I cannot run the test method after copying bearer token and defining it here as shown below.
Here is the its test method
@DisplayName("Get Order - Success Scenario")
@Test
void test_When_Order_Success() {
String bearerToken = "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJVc2VyIiwiaXNzIjoiUk9MRV9VU0VSICIsImlhdCI6MTY3MTQ4ODgyMiwiZXhwIjoxNjcxNDg4OTQyfQ.g83kKmFzDH539ZcpxM9D8bE_famFOevkOqNst_E8YG07b4yR4cEqcrySvz36vw8GJxTKm9gUQIM1J_G8cC5RGQ";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Bearer " + bearerToken);
HttpEntity<String> request = new HttpEntity<String>(headers);
//Mocking
Order order = getMockOrder();
when(orderRepository.findById(anyLong()))
.thenReturn(Optional.of(order));
when(restTemplate.exchange(
"http://PRODUCT-SERVICE/product/" + order.getProductId(),
HttpMethod.GET, request, ProductResponse.class).getBody()).thenReturn(getMockProductResponse());
when(restTemplate.exchange(
"http://PAYMENT-SERVICE/payment/order/" + order.getId(),
HttpMethod.GET, request, PaymentResponse.class).getBody()).thenReturn(getMockPaymentResponse());
//Actual
OrderResponse orderResponse = orderService.getOrderDetails(1,bearerToken);
//Verification
verify(orderRepository, times(1)).findById(anyLong());
verify(restTemplate, times(1)).getForObject(
"http://PRODUCT-SERVICE/product/" + order.getProductId(),
ProductResponse.class);
verify(restTemplate, times(1)).getForObject(
"http://PAYMENT-SERVICE/payment/order/" + order.getId(),
PaymentResponse.class);
//Assert
assertNotNull(orderResponse);
assertEquals(order.getId(), orderResponse.getOrderId());
}
Here is the error shown below.
java.lang.NullPointerException: Cannot invoke "org.springframework.http.ResponseEntity.getBody()" because the return value of "org.springframework.web.client.RestTemplate.exchange(String, org.springframework.http.HttpMethod, org.springframework.http.HttpEntity, java.lang.Class, Object[])" is null
How can I fix the issue?
Here is the repo : Link
To run the app,
-
Run Service Registery (Eureka Server)
-
Run config server
-
Run zipkin and redis through these commands shown below on docker
docker run -d -p 9411:9411 openzipkin/zipkin
docker run -d –name redis -p 6379:6379 redis -
Run api gateway
-
Run other services
2
Answers
You would have to first mock
restTemplate.exchange(...)
and return a mockedResponseEntity
. Then you can mockresponseEntity.getBody()
.Please note that RestTemplate is deprecated and should be replaced with WebClient: https://docs.spring.io/spring-framework/docs/5.2.2.RELEASE/javadoc-api/index.html?org/springframework/web/client/RestTemplate.html
In our project we’re using the following best practice:
Wrap the RestTemplate/ WebClient with a Client component, which does not provide any business logic, just a nice API.
We’re testing this class with SpringBootTest and Wiremock.
In the services we then can mock this custom client, which is much easier than mocking RestTemplate/ WebClient.
Instead of mocking the method, you can mock the response by using WireMock. This can make your test more realistic.
Also, calling
RestTemplate
means you are doing an integration test. This also means you are loading all yourspring
context and access your controller through a query you send with yourRestTemplate
and you don’t need to mock your repository nor your service. You can only mock an external service while doing an integration or and end to end test.