如何在 WebClient 单元测试中使用 MockWebServer 模拟错误响应
How to mock error response using MockWebServer in WebClient unit tests
我正在为使用 WebClient 调用 REST 端点的方法编写单元测试。
使用 MockWebServer,我能够覆盖成功响应的代码,但是
我找不到任何方法来模拟错误响应,以便与错误处理有关的相关代码也包含在单元测试中。
来源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));
});
}
}
测试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();
}
}
以上测试涵盖了代码的快乐路径,并适当标记了代码覆盖率。我怎样才能在这里模拟错误,以便它可以覆盖源代码中的以下几行 class 代码(关于错误场景)
// .onStatus(HttpStatus::isError, this.handleErrorResponse)
// .doOnError((throwable)-> { ......
您需要提供错误状态 4xx 或 5xxx。例如,
server.enqueue(
new MockResponse().setResponseCode(500)
.setHeader("content-type", "application/json")
.setBody("{}");
);
StepVerifier.create(employeeService.getPaymentInfo(new PaymentDataRequest())
.expectError()
.verify();
ps
我建议查看 WireMock which provides a very good API for testing web clients matchig . You could test posittive and negative scanarios including timeouts, retry logic using Scenarios or even simulate timeouts using Delays。
我正在为使用 WebClient 调用 REST 端点的方法编写单元测试。 使用 MockWebServer,我能够覆盖成功响应的代码,但是 我找不到任何方法来模拟错误响应,以便与错误处理有关的相关代码也包含在单元测试中。
来源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));
});
}
}
测试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();
}
}
以上测试涵盖了代码的快乐路径,并适当标记了代码覆盖率。我怎样才能在这里模拟错误,以便它可以覆盖源代码中的以下几行 class 代码(关于错误场景)
// .onStatus(HttpStatus::isError, this.handleErrorResponse)
// .doOnError((throwable)-> { ......
您需要提供错误状态 4xx 或 5xxx。例如,
server.enqueue(
new MockResponse().setResponseCode(500)
.setHeader("content-type", "application/json")
.setBody("{}");
);
StepVerifier.create(employeeService.getPaymentInfo(new PaymentDataRequest())
.expectError()
.verify();
ps
我建议查看 WireMock which provides a very good API for testing web clients matchig . You could test posittive and negative scanarios including timeouts, retry logic using Scenarios or even simulate timeouts using Delays。