当前位置: 首页 > 知识库问答 >
问题:

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

丁光华
2023-03-14

我正在为一个使用 WebClient 调用 REST endpoint的方法编写单元测试。使用MockWebServer,我能够涵盖成功响应的代码,但是我找不到任何方法来模拟错误响应,以便与错误处理相关的代码也包含在单元测试中。

源类:

@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));
      });
   }

}

测试类:

@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();
  }
   
}

上面的测试涵盖了代码的快乐路径,并适当地标记了代码覆盖率。我如何在这里模拟错误,以便它可以覆盖源代码中的以下行(关于错误场景)

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

.doOnError((throwable)-

共有1个答案

邴越彬
2023-03-14

您需要提供错误状态4xx或5xxx。例如,

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

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

ps

我建议查看WireMock,它为测试Web客户端匹配提供了一个非常好的API。您可以测试正反扫描,包括超时、使用场景重试逻辑,甚至可以使用延迟模拟超时。

 类似资料:
  • 为了获得可重用和可测试的rxjava代码,我使用ObservableTransformers分离了代码的各个部分。它在生产中工作得很好,但是测试它并不像预期的那么容易,因为我似乎无法模拟那些观察到的ransformers。 when(observableTransformer.apply(any())).thenreturn(observable.just(“mockedtext”)); 一旦调用

  • 在如何模拟Grails单元测试中使用的自动有线依赖方面,我可以提供一些建议。我省略了大部分不必要的代码,只给出了测试类和被测试文件类中的相关方法 如果不对此依赖性进行攻击或嘲弄,我就会得到错误 我尝试存根密码编码器并让它返回true 但这会给出一条错误消息: 有什么方法可以用Spock来嘲笑这种依赖吗?

  • 问题内容: 我正在使用RestTemplate 方法发布到端点。在我的测试文件中,我正在测试POST方法。但是用我目前的测试,我得到了POST请求。在测试文件中发出POST请求时,我需要模拟API的帮助 这是我的主文件 这是我的测试文件 问题答案: 您正在测试DataTestRepo类内部的逻辑,因此您不应模拟它。RestTemplate是DataTestRepo内部的一个依赖项,因此这正是您需要

  • 问题内容: 我知道关于模拟和测试有很多问题,但是我发现没有任何问题可以完美地帮助我,因此我仍然对理解以下内容有疑问: 如果我弄错了,请纠正我,但据我所知,单元测试用于隔离测试一个特定类的业务逻辑,并且如果有外部需要的任何对象,它们将被模拟。因此,例如,如果我有一个简单城市居民的管理系统,该系统将居民添加到列表中并按姓名返回居民(假设:居民仅包含一些基本个人信息),如下所示: 如果现在我要进行单元测

  • 我在尝试包装我的代码以用于单元测试时遇到了一些问题。问题是。我有接口IHttpHandler: 现在很明显,我将在Connection类中有一些方法,这些方法将从my后端检索数据(JSON)。但是,我想为这个类编写单元测试,显然我不想编写针对真实后端的测试,而是一个被嘲弄的测试。我曾尝试谷歌一个很好的答案,但没有很大的成功。我以前可以并且曾经使用过Moq来模拟,但是从来没有在像HttpClient