首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >MockMvc与SpringBootTest一起在测试控制器时抛出异常HttpMediaTypeNotSupportedException

MockMvc与SpringBootTest一起在测试控制器时抛出异常HttpMediaTypeNotSupportedException
EN

Stack Overflow用户
提问于 2022-07-05 19:38:51
回答 2查看 424关注 0票数 0

我正在Spring RestController中使用集成测试和MockMvc测试来测试请求验证。

ControllerTest.java

代码语言:javascript
运行
复制
@ExtendWith(MockitoExtension.class)
@SpringBootTest(classes = Controller.class)
@AutoConfigureMockMvc(addFilters = false)
class ControllerTest {

    private ObjectMapper objectMapper;

    @MockBean
    private Service service;

    @Autowired
    private MockMvc mockMvc;

    @BeforeEach
    void setUp() {
        objectMapper = new ObjectMapper();
    }

    @Test
    void createOrAdd_shouldReturnErrorResponseOnInvalidInput() throws Exception {
        Request request = Request.builder()
                .name("name<script>")
                .primaryEmail("test@mail.com")
                .build();

        mockMvc.perform(MockMvcRequestBuilders.post("/api/create")
                        .accept(MediaType.APPLICATION_JSON)
                        .contentType(MediaType.APPLICATION_JSON_VALUE)
                        .content(objectMapper.writeValueAsString(request))
                .characterEncoding("utf-8"))
                .andExpect(MockMvcResultMatchers.status().isBadRequest());
    }
}

Controller.java :

代码语言:javascript
运行
复制
@Slf4j
@RestController
public class Controller {

    private final Service service;

    public Controller(Service service) {
        this.service = service;
    }

    @PostMapping(value = "/api/create", consumes = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<GenericResponse<Response>> createOrAdd(@RequestBody @Valid Request request, Errors errors) {
        GenericResponse<Response> genericResponse = new GenericResponse<>();
        try {
            if (errors.hasErrors()) {
                throw new RequestParamsException(errors.getAllErrors());
            }
            Response response = service.createOrAdd(request);
            genericResponse.setData(response);
            return ResponseEntity.ok().body(genericResponse);
        } catch (RequestParamsException ex) {
            genericResponse.setErrors(ex.getErrors());
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(genericResponse);
        }
    }

错误

代码语言:javascript
运行
复制
WARN 17304 --- [           main] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/json;charset=utf-8' not supported]

MockHttpServletRequest:
      HTTP Method = POST
      Request URI = /api/create
       Parameters = {}
          Headers = [Content-Type:"application/json;charset=utf-8", Accept:"application/json", Content-Length:"162"]
             Body = {"name":"name<script>alert(1)</script>","primary_email_address":"test@mail.com"}
    Session Attrs = {}

Handler:
             Type = com.org.controller.Controller
           Method = com.org.controller.Controller#createOrAdd(Request, Errors)

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, multipart/mixed, */*"]
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

java.lang.AssertionError: Status expected:<400> but was:<415>
Expected :400
Actual   :415

在使用Content-TypeTest.java中调用mockMvc时,我使用了正确的Test.javaAccept头,但它仍然会给HttpMediaTypeNotSupportedException带来好处。在AcceptContent-Type中尝试了许多组合,但仍然无法工作。

我读过很多关于这个例外的问题,但是找不到问题所在。仍然无法弄清楚为什么它说的是HttpMediaTypeNotSupportedException。

Update:按照建议删除addFilters = false之后,无法找到处理程序本身。

代码语言:javascript
运行
复制
    MockHttpServletRequest:
          HTTP Method = POST
          Request URI = /api/create
           Parameters = {}
              Headers = [Content-Type:"application/json;charset=utf-8", Accept:"application/json", Content-Length:"162"]
                 Body = {"name":"name<script>alert(1)</script>","primary_email_address":"test@mail.com"}
    Session Attrs = {org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN=org.springframework.security.web.csrf.DefaultCsrfToken@7a687d8d}   

     
Handler:
             Type = null

Async:
    Async started = false
     Async result = null
    
    Resolved Exception:
             Type = null
    
    ModelAndView:
            View name = null
                 View = null
                Model = null
    
    FlashMap:
           Attributes = null
    
MockHttpServletResponse:
           Status = 403
    Error message = Forbidden
          Headers = [X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY"]
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

    
java.lang.AssertionError: Status expected:<400> but was:<403>
Expected :400
Actual   :403

请求

代码语言:javascript
运行
复制
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class CreateAgencyRequest {

    @NotNull(message = "name can't be null")
    @JsonProperty(value = "name")
    @Pattern(regexp = REGEX_CONST, message = "name is not valid")
    private String name;

    @NotNull(message = "primary_email_address can't be null")
    @JsonProperty(value = "primary_email_address")
    private String primaryEmail;

}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-07-06 08:19:44

让我们看看你的测试。

代码语言:javascript
运行
复制
@WebMvcTest(classes = Controller.class)
@AutoConfigureMockMvc(addFilters = false)
class ControllerTest {

    private ObjectMapper objectMapper;

    @MockBean
    private Service service;

    @Autowired
    private MockMvc mockMvc;

    @Test
    void createOrAdd_shouldReturnErrorResponseOnInvalidInput() throws Exception {
        Request request = Request.builder()
                .name("name<script>")
                .primaryEmail("test@mail.com")
                .build();

        mockMvc.perform(MockMvcRequestBuilders.post("/api/create")
                        .accept(MediaType.APPLICATION_JSON)
                        .contentType(MediaType.APPLICATION_JSON_VALUE)
                        .content(objectMapper.writeValueAsString(request))
                .characterEncoding("utf-8"))
                .andExpect(MockMvcResultMatchers.status().isBadRequest());
    }
}

首先,@ExtendWith(MockitoExtension.class)没有添加任何内容,因为您正在正确地使用由Spring处理的@MockBean注释。所以你应该把它去掉。

接下来,@SpringBootTest用于引导完整应用程序,以运行集成测试。您想要的是对web的切片测试,所以不要使用@SpringBootTest使用@WebMvcTest,这将使您的测试更快。然后,您也可以删除@AutoConfigureMockMvc,因为这是默认添加的。

您使用@AutoConfigureMockMvc(addFilters = false)禁用了所有过滤器,这可能是由于您获得了403个。所拥有的403是启用CSRF (默认情况下启用)而不是将其添加到请求中的结果。如果您不需要CSRF (您可能想要它),可以在中禁用它,或者如果您希望它修改您的请求。

查看错误,您的罪魁祸首是将characterEncoding添加到内容类型,因此您可能希望/应该删除它。

你的测试应该是这样的。

代码语言:javascript
运行
复制
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;

@WebMvcTest(Controller.class)
class ControllerTest {

    private ObjectMapper objectMapper = new ObjectMapper();

    @MockBean
    private Service service;

    @Autowired
    private MockMvc mockMvc;

    @Test
    void createOrAdd_shouldReturnErrorResponseOnInvalidInput() throws Exception {
        Request request = Request.builder()
                .name("name<script>")
                .primaryEmail("test@mail.com")
                .build();

        mockMvc.perform(MockMvcRequestBuilders.post("/api/create")
                        .with(csrf()) // Add CSRF field for security
                        .accept(MediaType.APPLICATION_JSON)
                        .contentType(MediaType.APPLICATION_JSON_VALUE)
                        .content(objectMapper.writeValueAsString(request))
                .andExpect(MockMvcResultMatchers.status().isBadRequest());
    }
}

注意:如果您也有身份验证,您可能还需要将用户/密码添加到请求中,作为在此解释

票数 1
EN

Stack Overflow用户

发布于 2022-07-05 20:14:21

我认为您缺少@WebMvcTest(controllers = Controller.class)

票数 -2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72874685

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档