Spring Boot 为什么此java WebClient模拟不起作用

qvtsj1bj  于 2022-11-05  发布在  Spring
关注(0)|答案(2)|浏览(166)

我的服务器通过WebClient发送一个请求,代码如下:

public String getResponse(String requestBody){
...
    WebClient.RequestHeadersSpec<?> request =
        client.post().body(BodyInserters.fromValue(requestBody));

    String resp =
        request.retrieve().bodyToMono(String.class)
            .doOnError(
                WebClientResponseException.class,
                err -> {
                  // do something
                })
            .block();

return resp;
}

我为它编写了一个单元测试,并希望模拟WebClient,以便我可以收到预期的响应:

when(webClientMock.post()).thenReturn(requestBodyUriMock);
when(requestBodyUriMock.body(BodyInserters.fromValue(requestBody))).thenReturn(requestHeadersMock);
when(requestHeadersMock.retrieve()).thenReturn(responseMock);
when(responseMock.bodyToMono(String.class)).thenReturn(Mono.just("response"));

String response = someServiceSpy.getResponse(requestBody);

assertEquals(Mono.just("response"), response);

但是,结果不是"response",而是一个html文件。我想我在什么地方犯了错误,但我不知道如何修复它。

yzxexxkh

yzxexxkh1#

getResponse方法中引用的client似乎没有设置为您在测试中创建的mock(webClientMock)。
如果在getResponse方法中创建这个client对象,我建议使用一个可以模仿的方法来创建它。

WebClient buildWebClient() {
  // build your webclient using the WebClientBuilder
}

您可能希望在此处抛出一个注解和/或一个@VisibleForTesting注解,以便明确此方法的存在,从而使测试更容易。
然后,您可以在someServiceSpy中存根此方法:

Mockito.doReturn(mockWebClient).when(someServiceSpy).buildWebClient();

这将确保您的mockWebClient在您的测试中用于您的getResponse方法。
此外,似乎您现有的代码需要稍微编辑一下。

when(requestBodyUriMock.body(BodyInserters.fromValue(requestBody))).thenReturn(requestHeadersMock);

应该是

when(requestBodyUriMock.body(eq(BodyInserters.fromValue(requestBody)))).thenReturn(requestHeadersMock);
50few1ms

50few1ms2#

我已经找到了直接模拟WebClient的解决方案,而不是将构建逻辑放入一个新的方法中来模拟它。我在这里编写了我的解决方案,以防将来其他人需要它:
让我把代码示例放在这里:

final WebClient client =
        WebClient.builder()
            .codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(someValue))
            .clientConnector(new ReactorClientHttpConnector(HttpClient.create(someProvider)))
            .baseUrl(someUrl)
            .defaultHeader(contentType, TEXT_XML_VALUE)
            .build();

    final WebClient.RequestHeadersSpec<?> request =
        client.post().body(BodyInserters.fromValue(reqBody));

首先,我们必须模拟WebClient的静态方法builder()。如果不模拟这个方法,mockito就不能编辑这个方法的行为,并且模拟的WebClient也不会被使用。我从这个StackOverflow问题的答案中发现了这一点;你可以阅读它了解更多的细节。:How to mock Spring WebClient and builder
用上面的方法模拟了builder()之后,你会得到一个模拟的WebClient,它类似于:

when(webClientBuilder.build()).thenReturn(webClientMock);

在我的示例代码中,client将调用post()body(),因此编写以下代码:

when(requestBodyUriMock.body(any())).thenReturn(requestHeadersMock);
    when(requestHeadersMock.retrieve()).thenReturn(responseMock);
    when(responseMock.bodyToMono(String.class)).thenReturn(Mono.just(expectedResponse));

我的单元测试一开始就返回了NPE,因为我使用了

when(requestBodyUriMock.body(BodyInserters.fromValue(requestBody))).thenReturn(requestHeadersMock);

而不是

when(requestBodyUriMock.body(any())).thenReturn(requestHeadersMock);

我认为这是因为代码不“认为”requestBodyUriMock正在使用BodyInserters.fromValue(requestBody的一些原因,我还不知道。

相关问题