简体   繁体   English

如何在 WebClient 单元测试中使用 MockWebServer 模拟错误响应

[英]How to mock error response using MockWebServer in WebClient unit tests

I am writing unit test for a method which uses WebClient to call a REST end point.我正在为使用 WebClient 调用 REST 端点的方法编写单元测试。 Using MockWebServer, I am able to cover the code for a success response, but I am unable to find any way to simulate error response so that the related code pertaining to error handling also gets covered in unit tests.使用 MockWebServer,我能够覆盖成功响应的代码,但我无法找到任何方法来模拟错误响应,因此与错误处理有关的相关代码也包含在单元测试中。

source class:来源 class:

@Service
@Slf4j
public class EmployeeService {

   private final WebClient webClient;
   private final PaymentServiceConfiguration paymentServiceConfiguration;
   
   public EmployeeService(WebClient webClient, PaymentServiceConfiguration paymentServiceConfiguration){
      this.webClient = webClient;
      this.paymentServiceConfiguration= paymentServiceConfiguration;

   }

   public Mono<PaymentDataResponse> getPaymentInfo(PaymentDataRequest paymentDataRequest){
      return webClient
             .post()
             .uri(paymentServiceConfiguration.getBaseUri() + "/payment")
             .body(Mono.just(paymentDataRequest, PaymentDataRequest.class)
             .retrieve()
             .onStatus(HttpStatus::isError, this.handleErrorResponse)
             .bodyToMono(PaymentDataResponse.class)
             .doOnError((throwable)-> {
                 log.error("Exception in getPaymentInfo method. Message {}", throwable.getMessage());
                 throw(Exceptions.propagate(throwable));
             });

   }

   private Mono<? extends Throwable> handleErrorResponse(ClientResponse clientResponse){
      Mono<String> errorMessage = clientResponse.bodyToMono(String.class);
      return errorMessage.flatMap((message) -> {
         log.error("Error response code is: {}, and the message is: {} ", clientResponse.rawStatusCode(), message);
         return Mono.error(new RuntimeException(message));
      });
   }

}

Test Class:测试Class:

@RunWith(MockitoJunitRunner.class)
public class EmployeeServiceTest {
   private MockWebServer server;
   private EmployeeService employeeService;
   private PaymentServiceConfiguration paymentServiceConfiguration;
   private String paymentServiceUri;

   @Before
   public void setUp() throws IOException{
     paymentServiceConfiguration = mock(PaymentServiceConfiguration.class);
     paymentServiceUri = "/paymentdomain.com";
     employeeService = new EmployeeService(WebClient.create(), paymentServiceConfiguration);
     server = new MockWebServer();
     
     server.start();
   }

  @Test
  public testPaymentInfo() throws IOException, InterruptedException {
     when(paymentServiceConfiguration.getBaseUri()).thenReturn(server.url(paymentServiceUri).url.toString());

     String result = "{\"paymentId\": 101, "\paymentType\": \"online\"}";

     server.enque(
         new MockResponse.setResponseCode(200)
                 .setHeader("content-type", "application/json")
                 .setBody(result);
     );
     
     StepVerifier.create(employeeService.getPaymentInfo(new PaymentDataRequest())
          .expectNext(new ObjectMapper.readValue(result, PaymentDataResponse.class))
          .expectComplete()
          .verify();
     
     RecordRequest request = server.takeRequest();
     Assert.assertEquals("POST", request.getMethod());
     Assert.assertEquals("/paymentdomain.com/payment", request.getPath());
  }

  @After
  public void tearDown() throws IOException {
     server.shutdown();
  }
   
}

Above test covers the happy path of code and marks the code coverage appropriately.上面的测试覆盖了代码的快乐路径,并适当地标记了代码覆盖率。 How can I mock an error here, so that it can cover the below lines in source class code (regarding error scenario)我怎样才能在这里模拟错误,以便它可以覆盖源代码 class 中的以下几行(关于错误场景)

//.onStatus(HttpStatus::isError, this.handleErrorResponse) //.onStatus(HttpStatus::isError, this.handleErrorResponse)

//.doOnError((throwable)-> {...... //.doOnError((throwable)-> {......

You need to provide error status 4xx or 5xxx.您需要提供错误状态 4xx 或 5xxx。 For example,例如,

server.enqueue(
        new MockResponse().setResponseCode(500)
                .setHeader("content-type", "application/json")
                .setBody("{}");
);

StepVerifier.create(employeeService.getPaymentInfo(new PaymentDataRequest())
        .expectError()
        .verify();

ps附言

I would recommend looking at WireMock which provides a very good API for testing web clients matchig.我建议查看WireMock ,它提供了一个非常好的 API 来测试 web 客户端 matchig。 You could test posittive and negative scanarios including timeouts, retry logic using Scenarios or even simulate timeouts using Delays .您可以测试正扫描和负扫描,包括超时、使用Scenarios重试逻辑,甚至使用Delays模拟超时。

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

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