When using MockMvcWebTestClient.bindToController to a controller with an annotated endpoint which returns null. Then the WebTestClient crashes when calling expectBody with the following message:
Content type 'application/octet-stream' not supported for bodyType=java.time.LocalDate
org.springframework.web.reactive.function.UnsupportedMediaTypeException: Content type 'application/octet-stream' not supported for bodyType=java.time.LocalDate
at org.springframework.web.reactive.function.BodyExtractors.readWithMessageReaders(BodyExtractors.java:205)
Suppressed: The stacktrace has been enhanced by Reactor, refer to additional information below:
Error has been observed at the following site(s):
*__checkpoint ⇢ Body from GET /date [DefaultClientResponse]
Expected behaviour is for it not to crash and for getResponseBody to return null.
Controller class:
package com.example.demo;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDate;
@RestController
public class DemoController {
@GetMapping(value = "date", produces = MediaType.APPLICATION_JSON_VALUE)
public LocalDate date() {
return null;
}
}
Test class:
package com.example.demo;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.client.MockMvcWebTestClient;
import java.time.LocalDate;
class DemoControllerTest {
@Test
void mvcTest() {
var client = MockMvcWebTestClient.bindToController(new DemoController())
.configureClient()
.build();
var res = client.get()
.uri("/date")
.accept(MediaType.APPLICATION_JSON)
.exchange()
.expectBody(LocalDate.class)
.returnResult()
.getResponseBody();
Assertions.assertThat(res).isNull();
}
}
Repository with reproducible example: https://github.com/gustavhagland/mock-mvc-issue
Comment From: gustavhagland
It seems like the method: ReactiveHttpInputMessage::getBody is returning a Flux with a single emit which is an empty buffer when it expects an empty Flux in the case where there is no response body
Comment From: rstoyanchev
The test expects a body wants to convert it to a date, but that can't be done when there is no actual body. BodyExtractors#readWithMessageReaders
finds no Content-Type header, defaults to "application/octet-stream", and predictably can't find a decoder from that to a date. The resulting UnsupportedMediaTypeException
is expected, and the same would occur with a regular (i.e. not a test) client.
The test should assert the server did return JSON successfully before trying to read the content:
.exchange()
.expectStatus().isOk() // <--
.expectHeader().contentType(MediaType.APPLICATION_JSON) // <--
.expectBody(LocalDate.class)
Results in an assertion failure:
17:44:45.123 [Test worker] ERROR org.springframework.test.web.reactive.server.ExchangeResult -- Request details for assertion failure:
> GET /date
> WebTestClient-Request-Id: [1]
> Accept: [application/json]
No content
< 200 OK OK
<
0 bytes of content (unknown content-type).
====================== MockMvc (Server) ===============================
MockHttpServletRequest:
HTTP Method = GET
Request URI = /date
Parameters = {}
Headers = [WebTestClient-Request-Id:"1", Accept:"application/json"]
Body = <no character encoding set>
Session Attrs = {}
Handler:
Type = com.example.demo.DemoController
Method = com.example.demo.DemoController#date()
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 200
Error message = null
Headers = []
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
Response header 'Content-Type'
Expected :application/json
Actual :null
Comment From: gustavhagland
Hello! Thank you for the response and sorry I took so long to respond. I can accept that that is the expected behaviour even though the assertion error is a bit misleading but the wierd thing is that the behaviour is not consistent when using WebTestClient.bindToController vs MockMvcWebTestClient.bindToController.
The test passes when using WebTestClient.bindToController instead. Is this a bug in that implementation? I updated the repo with an example.
Comment From: gustavhagland
I also added an example main function where I use both a RestClient and WebClient to fetch from the endpoint and both work i.e they both return null without errors
Comment From: gustavhagland
Friendly ping: @rstoyanchev. Understand if you're busy, just wanted to make sure that this was not forgotten