web-dev-qa-db-fra.com

Comment se moquer de Spring WebClient in Unit Test

Nous avons écrit une petite application Spring Boot REST, qui effectue une demande REST sur un autre noeud final REST.

@RequestMapping("/api/v1")
@SpringBootApplication
@RestController
@Slf4j
public class Application
{
    @Autowired
    private WebClient webClient;

    @RequestMapping(value = "/zyx", method = POST)
    @ResponseBody
    XyzApiResponse zyx(@RequestBody XyzApiRequest request, @RequestHeader HttpHeaders headers)
    {
        webClient.post()
            .uri("/api/v1/someapi")
            .accept(MediaType.APPLICATION_JSON)
            .contentType(MediaType.APPLICATION_JSON)
            .body(BodyInserters.fromObject(request.getData()))
            .exchange()
            .subscribeOn(Schedulers.elastic())
            .flatMap(response ->
                    response.bodyToMono(XyzServiceResponse.class).map(r ->
                    {
                        if (r != null)
                        {
                            r.setStatus(response.statusCode().value());
                        }

                        if (!response.statusCode().is2xxSuccessful())
                        {
                            throw new ProcessResponseException(
                                    "Bad status response code " + response.statusCode() + "!");
                        }

                        return r;
                    }))
            .subscribe(body ->
            {
                // Do various things
            }, throwable ->
            {
                // This section handles request errors
            });

        return XyzApiResponse.OK;
    }
}

Nous sommes nouveaux dans Spring et nous rencontrons des difficultés pour écrire un test unitaire pour ce petit extrait de code.

Existe-t-il un moyen élégant (réactif) de se moquer du client Web ou de démarrer un serveur fictif que le client Web peut utiliser comme point de terminaison?

9
Roman

Je pense que le support du printemps intégré est toujours en cours - https://jira.spring.io/browse/SPR-15286

J'aime vraiment wiremock pour (intégration-) tester de tels scénarios. Surtout parce que vous testez toute la sérialisation et la désérialisation avec cela. Avec wiremock, vous démarrez un serveur qui traite vos demandes en utilisant des stubs prédéfinis.

2
Mathias Dpunkt

Avec la méthode suivante, il était possible de simuler le Web Client avec Mockito pour des appels comme celui-ci:

webClient
.get()
.uri(url)
.header(headerName, headerValue)
.retrieve()
.bodyToMono(String.class);

ou

webClient
.get()
.uri(url)
.headers(hs -> hs.addAll(headers));
.retrieve()
.bodyToMono(String.class);

Méthode factice:

private static WebClient getWebClientMock(final String resp) {
    final var mock = Mockito.mock(WebClient.class);
    final var uriSpecMock = Mockito.mock(WebClient.RequestHeadersUriSpec.class);
    final var headersSpecMock = Mockito.mock(WebClient.RequestHeadersSpec.class);
    final var responseSpecMock = Mockito.mock(WebClient.ResponseSpec.class);

    when(mock.get()).thenReturn(uriSpecMock);
    when(uriSpecMock.uri(ArgumentMatchers.<String>notNull())).thenReturn(headersSpecMock);
    when(headersSpecMock.header(notNull(), notNull())).thenReturn(headersSpecMock);
    when(headersSpecMock.headers(notNull())).thenReturn(headersSpecMock);
    when(headersSpecMock.retrieve()).thenReturn(responseSpecMock);
    when(responseSpecMock.bodyToMono(ArgumentMatchers.<Class<String>>notNull()))
            .thenReturn(Mono.just(resp));

    return mock;
}
0
Igors Sakels