Spring 5.0.0 MockMvc:即使设置了正确的 MediaType,也不支持媒体类型

the*_*ard 3 java spring spring-mvc spring-test-mvc mockmvc

我将 JUnit4 与 Spring Web MVC Test 一起使用,并且我有控制器的测试类。

控制器使用 JSON 正文内容处理对“/test”的 POST 请求。我已经使用 Postman 手动测试了此方法,并且正如预期的那样收到了 400 Bad Request 响应,因为“name”属性为空。

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

{
    "name": ""
}
Run Code Online (Sandbox Code Playgroud)

但是,当我通过测试类向控制器发送相同的请求时,即使请求相同,我也会收到 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());
    }
}
Run Code Online (Sandbox Code Playgroud)

这是 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) {
    }
}
Run Code Online (Sandbox Code Playgroud)

这是 MyDTO。

@lombok.Data
public class MyDTO {
    private String name;
}
Run Code Online (Sandbox Code Playgroud)

我的依赖中也有杰克逊。

这是测试类的请求打印到控制台时的样子:

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 = []
Run Code Online (Sandbox Code Playgroud)

无论如何,为什么我会收到这个错误?这个请求对我来说看起来完全没问题。任何帮助表示赞赏。谢谢。

the*_*ard 6

我通过使用 @EnableWebMvc 注释 MyControllerTestConfiguration 内部静态类解决了该问题。

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

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

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

    }
Run Code Online (Sandbox Code Playgroud)