Mocking a WebClient post when there's a request body
Solution 1
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));
}
Solution 2
After adding headers in my WebClient code It starts to work like a magic
@Test
public void postMethod() {
when(webClient.post()).thenReturn(requestBodyUriMock);
when(requestBodyUriMock.uri(anyString())).thenReturn(requestBodyMock);
when(requestBodyMock.header(any(),any())).thenReturn(requestBodyMock);
when(requestHeadersMock.header(any(),any())).thenReturn(requestHeadersMock);
when(requestBodyMock.accept(any())).thenReturn(requestBodyMock);
when(requestBodyMock.contentType(any())).thenReturn(requestBodyMock);
when(requestBodyMock.body(any())).thenReturn(requestHeadersMock);
when(requestHeadersMock.retrieve()).thenReturn(responseMock);
when(responseSpec.bodyToMono(String.class))
.thenReturn(Mono.just("output"));
//WebClient call
TestResponse test = service.testMethod(mockObject);
assertEquals(test.Status(), 200);
}
Solution 3
You do not need to create a new RestClient()
if you are using @InjectMocks
.
Also Since you are mocking WebClient
you do not need to mock WebClient.
*` .
So the code becomes
@Mock
WebClient webClient;
@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);
}
AliReza
I like programming, software development and microservice architecture.
Updated on July 09, 2022Comments
-
AliReza almost 2 years
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?