有请求时模拟 WebClient post body

Mocking a WebClient post when there's a request body

关于模拟 WebClient object,有几个问题和有用的答案。但是我在用 body 做 post 时仍然有问题。我只是在使用 Mockito 而不是 mockwebserver

这是我正在测试的方法:

public class RestClient extends BaseRestClient {
 ...
 public <T,G> Mono<T> post(String url, G req, Class<T> resp) throws IOException {
        Mono<T> response = null;

        response = this.getWebClient().post()
                    .uri(url)
                    .header(HttpHeaders.CONTENT_TYPE,JSON_CONTENT_TYPE)
                    .accept(MediaType.APPLICATION_JSON)
                    //.body(BodyInserters.fromObject(req))
                    .header(HttpHeaders.AUTHORIZATION, BEARER + token)
                    .retrieve()
                    .bodyToMono(resp).log();

        return response.map(resp::cast);
    }
 ...

注意注释掉的 body 行。

这是与上面的代码配合使用的测试 - 再次注意测试中注释掉的行:

@Mock
WebClient webClient;

@Mock
WebClient.RequestBodyUriSpec requestBodyUriSpec;

@Mock
WebClient.RequestHeadersSpec requestHeadersSpec;

@Mock
WebClient.RequestBodySpec requestBodySpec;

@Mock
WebClient.ResponseSpec responseSpec;

@InjectMocks
RestClient restClient;

@Test
    public void postTest() throws IOException {
        when(webClient.post()).thenReturn(requestBodyUriSpec);
        when(requestBodyUriSpec.uri(anyString())).thenReturn(requestBodySpec);
        when(requestBodySpec.header(any(),any())).thenReturn(requestBodySpec);
        when(requestBodySpec.accept(any())).thenReturn(requestBodySpec);
        when(responseSpec.bodyToMono(ArgumentMatchers.<Class<String>>notNull()))
                .thenReturn(Mono.just("resp"));

        //when(requestBodySpec.body(any())).thenReturn(requestHeadersSpec);
        when(requestBodySpec.retrieve()).thenReturn(responseSpec);

        restClient.post("http://sampleurl",Object.class, Object.class);
    }

同样,一切正常。但是,如果我将注释掉的行放回代码中,这意味着此 post 有一个 body,并通过将注释掉的行放回测试中来模拟 body,那么我在代码中 .retrieve() 上会得到 NullPointerException。就像我缺少一个 object 来模拟一样。

我什至为 requestHeadersSpecrequestBodyUriSpec:

嘲笑 .retrieve()
when(requestHeadersSpec.retrieve()).thenReturn(responseSpec);
when(requestBodyUriSpec.retrieve()).thenReturn(responseSpec);

仍然没有成功。有什么想法吗?

如果您使用 @InjectMocks,则无需创建 new RestClient()。 此外,由于您正在嘲笑 WebClient,因此您不需要嘲笑 WebClient.*` .

所以代码变成

@Mock
WebClient webClient;

@InjectMocks
RestClient restClient;

@Test
    public void postTest() throws IOException {
        when(webClient.post()).thenReturn(requestBodyUriSpec);
        when(requestBodyUriSpec.uri(anyString())).thenReturn(requestBodySpec);
        when(requestBodySpec.header(any(),any())).thenReturn(requestBodySpec);
        when(requestBodySpec.accept(any())).thenReturn(requestBodySpec);
        when(responseSpec.bodyToMono(ArgumentMatchers.<Class<String>>notNull()))
                .thenReturn(Mono.just("resp"));

        //when(requestBodySpec.body(any())).thenReturn(requestHeadersSpec);
        when(requestBodySpec.retrieve()).thenReturn(responseSpec);

        restClient.post("http://sampleurl",Object.class, Object.class);
    }

我错过了模拟 requestHeadersSpec 的 "header" 方法:

when(requestHeadersSpec.header(any(),any())).thenReturn(requestHeadersSpec);

所以,这现在工作正常:

@Test
    public void postTest() throws IOException {
        when(webClient.post()).thenReturn(requestBodyUriSpec);
        when(requestBodyUriSpec.uri(anyString())).thenReturn(requestBodySpec);
        when(requestBodySpec.header(any(),any())).thenReturn(requestBodySpec);

        when(requestHeadersSpec.header(any(),any())).thenReturn(requestHeadersSpec);

        when(requestBodySpec.accept(any())).thenReturn(requestBodySpec);
        when(requestBodySpec.body(any())).thenReturn(requestHeadersSpec);
        when(requestHeadersSpec.retrieve()).thenReturn(responseSpec);
        when(responseSpec.bodyToMono(ArgumentMatchers.<Class<String>>notNull()))
                .thenReturn(Mono.just("resp"));

        Assert.assertNotNull(restClient.post("http://sampleurl",Object.class, Object.class));
    }

在我的 WebClient 代码中添加 headers 之后它开始像魔术一样工作

    @Test
    public void postMethod() {
        when(webClient.post()).thenReturn(requestBodyUriMock);
        when(requestBodyUriMock.uri(anyString())).thenReturn(requestBodyMock);
        when(requestBodyMock.header(any(),any())).thenReturn(requestBodyMock);

        when(requestHeadersMock.header(any(),any())).thenReturn(requestHeadersMock);

        when(requestBodyMock.accept(any())).thenReturn(requestBodyMock);
        when(requestBodyMock.contentType(any())).thenReturn(requestBodyMock);
        when(requestBodyMock.body(any())).thenReturn(requestHeadersMock);
        when(requestHeadersMock.retrieve()).thenReturn(responseMock);
        when(responseSpec.bodyToMono(String.class))
                .thenReturn(Mono.just("output"));
    
        //WebClient call
        TestResponse test = service.testMethod(mockObject);
        assertEquals(test.Status(), 200);
    }

模拟 webclient post 方法与 request-body

示例:-

List<ParamountRxPriceResponse> paramountRxPriceResponse = paramountRxWebClient.post()
                    .uri(paramountRxuri.toString()).contentType(MediaType.APPLICATION_JSON)
                    .accept(MediaType.APPLICATION_JSON).bodyValue(paramountRxPriceRequest).retrieve()
                    .bodyToMono(new ParameterizedTypeReference<List<ParamountRxPriceResponse>>() {
                    }).block();

模拟的测试用例。

@Test
public void testSbuildBaseBPricingFormat() {


    when(webClientMock.post()).thenReturn(requestBodyUriMock);
    when(requestBodyUriMock.uri(Mockito.anyString())).thenReturn(requestBodyMock);
    when(requestBodyMock.contentType(Mockito.any())).thenReturn(requestBodyMock);
    when(requestBodyMock.accept(Mockito.any())).thenReturn(requestBodyMock);
    when(requestBodyMock.bodyValue(ArgumentMatchers.any())).thenReturn(requestHeadersMock);
    when(requestHeadersMock.retrieve()).thenReturn(responseMock);
    when(responseMock.bodyToMono(ArgumentMatchers.<ParameterizedTypeReference<List<ParamountRxPriceResponse>>>any())).thenReturn(Mono.just(getParamountRxPriceResponse()));
    CompletableFuture<PricingResponse> actulaResultResponse = paramountRxResponseBuilderService
            .buildBasePricingFormat(webClientMock,ProductInfoRequest.builder().formulationId("32332332332").quantity("10").zipCode("423894").build() ,"https://testUri.com","2323321");
    assertNotNull(actulaResultResponse);

}