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
CodePudding user response:
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());
You would have to first mock restTemplate.exchange(...)
and return a mocked ResponseEntity
. Then you can mock responseEntity.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.
CodePudding user response:
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 your spring
context and access your controller through a query you send with your RestTemplate
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.