简体   繁体   English

Spring Boot微服务-JUnit测试中RestTemplate空指针异常

[英]Spring Boot Microservices - RestTemplate Null Pointer Exception in JUnit Test

I have a problem running Junit Service in my spring-boot microservice.我在我的spring-boot微服务中运行 Junit 服务时遇到问题。 I defined bearer token getting from /authenticate/login .我定义了从/authenticate/login获取的不记名令牌。 It is valid.这是有效的。 I can send a request to any service through Postman.我可以通过 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,要运行该应用程序,

  1. Run Service Registery (Eureka Server)运行服务注册(尤里卡服务器)

  2. Run config server运行配置服务器

  3. Run zipkin and redis through these commands shown below on docker通过下面显示的这些命令在 docker 上运行 zipkin 和 redis

    docker run -d -p 9411:9411 openzipkin/zipkin docker run -d --name redis -p 6379:6379 redis docker run -d -p 9411:9411 openzipkin/zipkin docker run -d --name redis -p 6379:6379 redis

  4. Run api gateway运行 api 网关

  5. Run other services运行其他服务

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 .您必须首先模拟restTemplate.exchange(...)并返回模拟的ResponseEntity Then you can mock responseEntity.getBody() .然后你可以模拟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请注意,RestTemplate 已弃用,应替换为 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.用一个客户端组件包装 RestTemplate/WebClient,它不提供任何业务逻辑,只是一个很好的 API。 We're testing this class with SpringBootTest and Wiremock.我们正在使用 SpringBootTest 和 Wiremock 测试此类。 In the services we then can mock this custom client, which is much easier than mocking RestTemplate/ WebClient.然后在服务中我们可以模拟这个自定义客户端,这比模拟 RestTemplate/WebClient 容易得多。

Instead of mocking the method, you can mock the response by using WireMock .您可以使用WireMock来模拟响应,而不是模拟该方法。 This can make your test more realistic.这可以使您的测试更加真实。

Also, calling RestTemplate means you are doing an integration test.此外,调用RestTemplate意味着您正在进行集成测试。 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.这也意味着您正在加载所有spring上下文并通过您使用RestTemplate发送的查询访问您的控制器,并且您不需要模拟您的存储库或您的服务。 You can only mock an external service while doing an integration or and end to end test.您只能在进行集成或端到端测试时模拟外部服务。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM