Issue
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?
Solution
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));
}
Answered By - Alireza