Spring2.7+JUnit5单元测试MockMvc contentType方法未定义报错
问题原因
报错和依赖缺失没有关系,是三处写法错误叠加导致的:
- 核心错误:链式调用的括号位置写错了。
contentType()、content()是请求构造器MockHttpServletRequestBuilder的方法,需要写在get()/post()的调用链上;你提前闭合了perform()方法的括号,相当于在perform()返回的ResultActions对象上调用这些方法,而ResultActions根本没有定义contentType方法,IDE自然提示方法未定义。 - 测试框架注解混用:你导入的是JUnit5的
@Test注解(包路径org.junit.jupiter.api.Test),但类上用的是JUnit4专属的@RunWith(SpringRunner.class),二者不兼容,即使修好链式调用问题,也会出现上下文加载失败的错误。 - 请求方法不匹配:产品创建是写操作,标准实现用POST请求,你用
get()构造了GET请求,即使语法正确,也会因为接口请求方法不匹配返回405错误。 - 额外隐患:代码中用到的
mockMvc、repo对象没有加对应注入注解,运行时会报空指针。
修复步骤
- 清理无效导入和错误注解:删除JUnit4相关的
@RunWith注解和对应导入,JUnit5环境下@WebMvcTest已经内置了Spring测试扩展,不需要额外指定运行器。 - 修正MockMvc调用结构:把
contentType、content等请求属性配置挪到请求构造器的调用链内部,最后再把完整的请求构造器传入perform()方法。 - 替换请求方法:把GET请求构造器换成POST,补全缺失的静态导入。
- 为依赖对象添加必要的注入注解。
修复后可运行代码
首先是导入部分,删除无效导入、补全缺失项:
import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectWriter; // 替换成你自己项目中Product、Repository、Controller的实际包路径 import com.example.demo.entity.Product; import com.example.demo.repository.ProductRepository; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc;
测试类代码:
// 指定要测试的Controller类,避免加载全量Web上下文拖慢测试速度 @WebMvcTest(ProductController.class) class RestControllerMvcTests { @Autowired private MockMvc mockMvc; @MockBean private ProductRepository repo; // 替换成你项目实际的接口路径、上下文路径 private static final String PRODUCT_URL = "/product"; private static final String CONTEXT_URL = "/api"; @Test public void testCreateProduct() throws Exception { Product product = buildProduct(); when(repo.save(any())).thenReturn(product); ObjectWriter objwrite = new ObjectMapper().writer().withDefaultPrettyPrinter(); // 注意括号层级:所有请求配置都在post()的调用链上,最后再传入perform mockMvc.perform(post(PRODUCT_URL) .contextPath(CONTEXT_URL) .contentType(MediaType.APPLICATION_JSON) .content(objwrite.writeValueAsString(product))) .andExpect(status().isOk()); } private Product buildProduct() { Product product = new Product(); // 补全测试对象的字段赋值 return product; } }
额外说明
- 如果确实要测试GET接口,不要加
.content()传递请求体,HTTP规范中GET请求不推荐携带请求体,不同容器对这类请求的处理逻辑不一致,容易出现偶发错误。 - Spring Boot 2.7默认使用JUnit5作为测试框架,不要引入任何
org.junit.runner、org.junit.Test开头的JUnit4相关类,避免出现框架兼容问题。
内容的提问来源于stack exchange,提问作者c513-oz
相关产品推荐
相关产品推荐

