Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking a WebClient post when there's a request body

There are several questions with helpful answers about mocking a WebClient object. But I still have problems when doing a post with a body. I'm just using Mockito not mockwebserver.

This is the method I'm testing:

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

Notice the commented out body line.

And this is the test which works fine with the code above- again notice the commented out line in the test:

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

Again, everything works fine. But if I put the commented out line back in the code, meaning there's a body to this post, and mock the body by putting the commented out line back in the test, then I'll get NullPointerException on .retrieve() in the code. Just like I'm missing an object to mock.

I even mocked .retrieve() for requestHeadersSpec and requestBodyUriSpec:

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

And still no success. Any ideas what's wrong there?

like image 503
AliReza Avatar asked Nov 17 '19 14:11

AliReza


People also ask

How do you mock a WebClient call?

We have two main options for mocking in our tests: Use Mockito to mimic the behavior of WebClient. Use WebClient for real, but mock the service it calls by using MockWebServer (okhttp)


1 Answers

I missed mocking the "header" method of requestHeadersSpec:

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

So, this works fine now:

@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));
    }
like image 129
AliReza Avatar answered Sep 26 '22 09:09

AliReza