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