JUnit4转JUnit5:@RunWith改@ExtendWith后Spring Boot测试报错求助
解决JUnit5迁移中@WebMvcTest与Mockito混用导致的Bean找不到问题
我来帮你理清楚这个问题的根源,以及对应的解决方案:
问题根源分析
你遇到的NoSuchBeanDefinitionException主要是因为以下几个冲突和使用不当:
- @WebMvcTest的作用范围:这个注解是Spring Boot的「测试切片」,它只会加载Web层相关的Bean(比如你的
HappyPostController),不会自动加载业务层的HappyPostService。但你的控制器通过构造器依赖HappyPostService,Spring容器启动时找不到这个Bean,所以报错。 - 测试方式混用:你同时用了Spring的
@WebMvcTest(会自动装配控制器)和Mockito的@Mock/@InjectMocks(手动创建控制器),两种方式互相冲突——Spring还是会尝试初始化容器内的控制器实例,但找不到依赖的Service。 - 弃用属性:
@WebMvcTest的secure=false已经被弃用,虽然不是当前报错的原因,但后续建议替换成@AutoConfigureMockMvc(secure = false)。
解决方案一:Spring官方推荐的Web层测试方式(@WebMvcTest + @MockBean)
这是最贴合Spring Boot测试最佳实践的方案,用@MockBean让Spring自动创建并注入Mock的Service到控制器中,不需要手动构建控制器和MockMvc:
@ExtendWith(SpringExtension.class) @WebMvcTest(HappyPostController.class) // 替代弃用的secure=false,关闭安全校验 @AutoConfigureMockMvc(secure = false) public class HappyPostControllerTest { // Spring自动配置MockMvc @Autowired private MockMvc mockMvc; // 让Spring创建一个Mock的Service并加入容器,自动注入到控制器 @MockBean private HappyPostServiceImpl happyPostService; // Spring自动注入控制器实例(已经包含Mock的Service) @Autowired private HappyPostController happyPostController; @Test public void testMockCreation() { Assertions.assertNotNull(happyPostService); Assertions.assertNotNull(mockMvc); Assertions.assertNotNull(happyPostController); } // 示例:测试接口返回 @Test public void testGetHappyPostSuccess() throws Exception { // Mock Service的返回值 HappyPost mockPost = new HappyPost(); mockPost.setId(1L); mockPost.setTitle("Test Happy Post"); when(happyPostService.getPostById(1L)).thenReturn(mockPost); // 执行请求并验证结果 mockMvc.perform(get("/posts/1") .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(jsonPath("$.id").value(1L)) .andExpect(jsonPath("$.title").value("Test Happy Post")); } }
解决方案二:纯Mockito手动测试(不加载Spring容器)
如果你想完全脱离Spring容器,只测试控制器逻辑,可以去掉Spring相关的测试注解,手动构建MockMvc:
@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class HappyPostControllerTest { private MockMvc mockMvc; @Mock private HappyPostServiceImpl happyPostService; private HappyPostController happyPostController; @BeforeAll public void initialize() { // 替换弃用的initMocks,初始化Mockito环境 MockitoAnnotations.openMocks(this); // 手动创建控制器,注入Mock的Service happyPostController = new HappyPostController(happyPostService); // 构建独立的MockMvc this.mockMvc = MockMvcBuilders .standaloneSetup(happyPostController) .build(); } @Test public void testMockCreation() { Assertions.assertNotNull(happyPostService); Assertions.assertNotNull(mockMvc); Assertions.assertNotNull(happyPostController); } // 其他测试方法... }
额外注意点
- 方案一的优势是能自动配置Web层的各种组件(比如消息转换器、全局异常处理器),测试更贴近真实运行环境。
- 方案二更轻量,适合快速验证控制器的核心逻辑,不需要启动Spring容器。
- 注意
MockitoAnnotations.initMocks(this)已被弃用,建议使用MockitoAnnotations.openMocks(this)。
内容的提问来源于stack exchange,提问作者shovon
相关产品推荐
相关产品推荐

