0

I have this request with WebClient:

webClient
   .get()
   .uri(uri)
   .accept(MediaType.APPLICATION_OCTET_STREAM)
   .<Optional<ByteArrayResource>>exchangeToMono(response -> {
          if (response.statusCode().equals(HttpStatus.NOT_FOUND)) {
                return Mono.just(Optional.empty());
          }
          return response.bodyToMono(ByteArrayResource.class).map(Optional::of);
      })
   .block();

How can I test the logic inside exchangeToMono()?

I'm using Mockito for testing this way: given(headersSpecHeadOpMock.exchangeToMono()).willReturn(Mono.just(clientResponse))

But the problem here is that this way I'm not testing the HttpStatus.NOT_FOUND.

João Dias
  • 16,277
  • 6
  • 33
  • 45

3 Answers3

1

The problem I was having is that I was mocking the ClientResponse, but I would have to Mock a Function<ClientResponse, ? extends Mono<Optional<ByteArrayResource>>>.

The solution was to use an ArgumentCaptor to get the argument and then make the assert of his value like this:

ArgumentCaptor declaration:

ArgumentCaptor<Function<ClientResponse, ? extends Mono<Optional<ByteArrayResource>>>> captorLambda = ArgumentCaptor.forClass(Function.class);

Capture the argument:

given(headersSpecGetOpMock.<Optional<ByteArrayResource>>exchangeToMono(captorLambda.capture())).willReturn(Mono.just(Optional.empty()));

Assert the value returned by the client response:

assertThat(captorLambda.getValue().apply(clientResponse).block()).isEqualTo(Optional.empty());```
0

Consider rewriting your code as follows:

webClient
   .get()
   .uri(uri)
   .accept(MediaType.APPLICATION_OCTET_STREAM)
   .retrive()
   .onStatus(status -> HttpStatus.NOT_FOUND == status, response -> Mono.just(Optional.empty()))
   .bodyToMono(ByteArrayResource.class);
   .map(Optional::of)
   .block();

Now you can mock retrieve() method to test your conditions easily.

As a side note, please consider dropping block() call, this defeats the purpose of using reactive programming.

João Dias
  • 16,277
  • 6
  • 33
  • 45
  • Hi João and thanks for your reply, I understand what you mean, but I wanted to avoid using retrieve. I would like to use the ```exchangeToMono()```, because this method hands you the ClientResponse object itself along with the response status and headers and it gives us better control over the response like we can check [here](https://stackoverflow.com/questions/58410352/spring-boot-webclients-retrieve-vs-exchange). The problem I was having is that I was mocking the ClientResponse, but I would have to Mock a ```Function>>```. – Gustavo Oliveira Oct 20 '21 at 09:33
0

You can use okhttp to mock the server you are hitting as shown here: https://www.baeldung.com/spring-mocking-webclient

The only issue is that you have to use the .mutate() method on the webclient you are trying to test to edit the basurl to match that of the mock webserver. In my own implementation, I used getters and setters to alter the webclient baseurl and then set it back to the original at the end of the test.

  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jan 06 '22 at 20:51