【问题标题】:Mocking a WebClient post when there's a request body有请求正文时模拟 WebClient 帖子
【发布时间】:2020-03-13 01:02:44
【问题描述】:

关于模拟 WebClient 对象,有几个问题提供了有用的答案。但是我在用身体发帖时仍然遇到问题。我只是使用 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);
    }
 ...

注意注释掉的正文行。

这是与上面的代码一起正常工作的测试——再次注意测试中注释掉的行:

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

再次,一切正常。但是,如果我将注释掉的行放回代码中,这意味着这篇文章有一个正文,并通过将注释掉的行放回测试中来模拟正文,那么我将获得 NullPointerException .retrieve() 在代码中。就像我缺少要模拟的对象一样。

我什至为 requestHeadersSpecrequestBodyUriSpec 模拟了 .retrieve():

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

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

【问题讨论】:

  • 完全模拟webclient 太可怕了,但这是唯一的方法
  • 是的,不能同意更多:)
  • 有时问题可能是导入 org.junit.jupiter.api.Test 而不是 org.junit.Test;

标签: java spring unit-testing mockito webclient


【解决方案1】:

如果您使用的是@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);
    }

【讨论】:

  • 是的,我错误地实例化了restClient。感谢您指出!不要认为这就是它不起作用的原因。应该在问题中解决它,以免让更多人感到困惑 :) 但是,如果您没有模拟这些 WebClient.* 对象,您的代码 sn-p 来自哪里?
  • 既然你已经模拟了 WebClient,那么 WebClient 中的所有方法都可以被模拟,而无需显式地模拟它们。该建议对您的情况也有效
  • 但是你的代码sn-p中仍然有它们。像“when(webClient.post()).thenReturn(requestBodyUriSpec);”其中有“requestBodyUriSpec”。这个物体是从哪里来的?
【解决方案2】:

我错过了嘲笑 requestHeadersSpec 的“标头”方法:

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

【讨论】:

  • 我仍然收到 NullPointerException,怀疑这一行`when(requestBodyUriSpec.uri(anyString())).thenReturn(requestBodySpec); 没有返回模拟,但我在我的代码中做同样的事情。
  • 如果你定义了模拟对象requestBodySpec,它应该被返回。
【解决方案3】:

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

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

【讨论】:

  • 酷!是的,添加标题对我也有帮助。这就是为什么我将上面的答案标记为已接受。
  • responseMock mock 来自哪里?
  • 您可以将其添加到您的测试类中。 @Mock private WebClient.RequestBodyUriSpec requestBodyUriMock;
  • 配置它就像... when(webClientMock.post()).thenReturn(requestBodyUriMock); when(requestBodyUriMock.uri('/uri')).thenReturn(requestBodyMock);
【解决方案4】:

使用 request-body 模拟 webclient post 方法

示例:-

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

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-06
    • 1970-01-01
    • 2022-01-25
    • 1970-01-01
    • 2016-08-11
    • 2019-11-28
    • 2019-06-01
    • 2012-03-31
    相关资源
    最近更新 更多