Spring 5.0.0 MockMvc: неподдерживаемый тип носителя, даже с правильным набором MediaType

Я использую JUnit4 с Spring Web MVC Test, и у меня есть тестовый класс для контроллера.

Контроллер обрабатывает запрос POST к «/test» с содержимым тела JSON. Я протестировал этот метод вручную с помощью Postman и получил ответ 400 Bad Request, как и ожидалось, поскольку свойство «имя» пусто.

POST /Server/test HTTP/1.1
Host: localhost:8080
Content-Type: application/json
Cache-Control: no-cache

{
    "name": ""
}

Однако, когда я отправляю тот же запрос на свой контроллер через свой тестовый класс, я получаю ошибку 415 (неподдерживаемый тип носителя), хотя запрос тот же.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@WebAppConfiguration
public class MyControllerTest {

@Configuration
public static class MyControllerTestConfiguration {

    @Bean
    public MyController myController() {
        return new MyController();
    }
}

private MockMvc mockMvc;

@Before
public void setup() {
    mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}

@Test
public void shouldReturnBadRequest_IfBodyIsEmpty() throws Exception {
    // Works fine
    mockMvc.perform(post("/test"))
           .andExpect(status().isBadRequest());
}

@Test
public void shouldReturnBadRequest_IfInvalidFields() throws Exception {

    MyDTO dto = new MyDTO();
    dto.setName("");

    // Jackson object mapper
    ObjectMapper mapper = new ObjectMapper();

    // TEST FAIL: Gets 415 error
    mockMvc.perform(
                post("/test")
                .content(mapper.writeValueAsString(dto))
                .characterEncoding("UTF-8")
                .contentType(MediaType.APPLICATION_JSON)
            )
            .andDo(print())
            .andExpect(status().isBadRequest());
    }
}

А вот и MyController.

@RestController
@EnableWebMvc
public class MyController {

    @RequestMapping(value = "/test", method = RequestMethod.POST)
    public void init(@javax.validation.Valid @RequestBody MyDTO dto) {
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public void validationError(MethodArgumentNotValidException ex) {
    }
}

А вот и MyDTO.

@lombok.Data
public class MyDTO {
    private String name;
}

У меня также есть Джексон в моих зависимостях.

Вот как выглядит запрос тестового класса, когда он выводится на консоль:

MockHttpServletRequest:
      HTTP Method = POST
      Request URI = /test
       Parameters = {}
          Headers = {Content-Type=[application/json;charset=UTF-8]}
             Body = {"name":""}
    Session Attrs = {}

Handler:
             Type = controller.MyController
           Method = public void controller.MyController.init(dto.MyDTO)

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = org.springframework.web.HttpMediaTypeNotSupportedException

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 415
    Error message = null
          Headers = {Accept=[application/octet-stream, text/plain, application/xml, text/xml, application/x-www-form-urlencoded, application/*+xml, multipart/form-data, */*]}
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

В любом случае, почему я получаю эту ошибку? Запрос выглядит совершенно нормально для меня. Любая помощь приветствуется. Спасибо.


person the duck wizard    schedule 09.10.2017    source источник
comment
Можете ли вы сказать мне, вернет ли тест 415, если вы опустите .characterEncoding("UTF-8") ?   -  person Aleh Maksimovich    schedule 09.10.2017
comment
@AlehMaksimovich Да, до сих пор.   -  person the duck wizard    schedule 09.10.2017
comment
Подозрительно, что MockHttpServletResponse Headers = {Accept=[application/octet-stream, ...]} не содержит application/json. Возможно, у вас нет библиотеки JSON, поддерживаемой Jackson или Spring, в пути к тестовому классу (зависимость во время выполнения?). Spring будет специально искать HttpMessageConverter, связанный с типом mime, для выполнения преобразования. Spring boot автоматически настраивает MappingJackson2MessageConverter, если Джексон находится на пути к классам.   -  person Aleh Maksimovich    schedule 09.10.2017
comment
@AlehMaksimovich Ну, ObjectMapper - это объект из пакета привязки данных Джексона, и он присутствует в MyControllerTest.java, и тест выполняется без ошибок компиляции. Означает ли это, что он находится в пути к классам?   -  person the duck wizard    schedule 10.10.2017
comment
Этот пост может содержать подсказку: stackoverflow.com/questions/25978022/ Я полагаю, что вы MappingJackson2MessageConverter не зарегистрированы, но с информацией в вашем вопросе я не могу сказать, почему.   -  person Aleh Maksimovich    schedule 10.10.2017
comment
В запросе вашего тестового класса Почему URI запроса /api/admin/init, как я понимаю, должен быть /Server/test, не так ли?   -  person Amit K Bist    schedule 10.10.2017
comment
@AmitKBist Плохо. Это URI в моих файлах, но я изменил его на /test в этом контексте, чтобы отделить его от моего проекта. Спасибо, что указали на это. (Во избежание недоразумений это не означает, что проблема решена.)   -  person the duck wizard    schedule 10.10.2017


Ответы (1)


Я решил проблему, аннотировав свой внутренний статический класс MyControllerTestConfiguration с помощью @EnableWebMvc.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@WebAppConfiguration
public class MyControllerTest {

    @Configuration
    @EnableWebMvc // <------------ added this
    public static class MyControllerTestConfiguration {

        @Bean
        public SetupController setupController() {
            return new MyController();
        }

    }
person the duck wizard    schedule 09.10.2017