SpringBoot执行gradle clean build报ApplicationContext加载失败
问题诊断
执行gradle clean build运行全量测试时抛出java.lang.IllegalStateException: Failed to load ApplicationContext、单测试类运行正常,移除@AutoConfigureMockMvc后报Could not autowire. No beans of 'MockMvc' type found,是以下几个问题叠加导致:
- 移除
@AutoConfigureMockMvc后找不到MockMvc属于预期现象:该注解是触发Spring自动配置MockMvc Bean的入口,删除后上下文里不会生成对应Bean,自然无法注入。 - 测试代码存在基础语法错误,直接阻断测试执行:
JobTest中Mock打桩语句缺失右括号:when(jobService.neededJob(anyString()).thenReturn(mockJob);- 两个测试类中使用的
mockJob、mockEmployer对象未定义初始化,会直接触发编译错误。
- JUnit版本注解混用:类上的
@RunWith(SpringRunner.class)是JUnit4的测试运行器注解,但@BeforeEach是JUnit5的生命周期注解,混用会导致测试初始化逻辑不执行,生命周期回调错乱。 - 重复配置MockMvc加剧上下文冲突:你已经通过
@AutoConfigureMockMvc让Spring自动注入配置好的MockMvc实例,又在@BeforeEach方法中手动通过MockMvcBuilders重新构建MockMvc实例赋值给注入的变量,会导致上下文Bean定义冲突。 - Spring测试上下文缓存冲突:Spring测试默认会按测试配置(包含
@MockBean标注的Bean列表)缓存ApplicationContext,两个测试类分别Mock了不同的Service Bean,会生成不同的上下文Key,重复加载上下文时如果存在残留的Bean定义就会抛出加载失败异常,这也是单测试类运行正常、同时运行失败的核心诱因。
修复方案
按以下步骤修改即可解决问题:
- 统一JUnit版本,消除注解混用
- 若使用JUnit4:将两个类中的
@BeforeEach替换为@Before,保留@RunWith(SpringRunner.class)注解。 - 若使用JUnit5(Spring Boot 2.2+默认推荐版本):删除类上的
@RunWith(SpringRunner.class)注解,@SpringBootTest注解已经默认集成了JUnit5的Spring扩展支持,不需要额外添加运行器注解。
- 若使用JUnit4:将两个类中的
- 修复基础语法错误
- 补全Mock打桩语句的右括号,将
when(jobService.neededJob(anyString()).thenReturn(mockJob);修改为when(jobService.neededJob(anyString())).thenReturn(mockJob); - 在测试类中提前定义并初始化
mockJob、mockEmployer对象,不要直接使用未声明的变量。
- 补全Mock打桩语句的右括号,将
- 删除重复的MockMvc配置
删掉两个测试类setup方法中手动构建MockMvc的代码(即this.mockMvc = MockMvcBuilders.webAppContextSetup(applicationContext).build();这行),@AutoConfigureMockMvc已经自动完成了MockMvc的构建和注入,不需要重复赋值。 - 添加上下文清理注解(可选,兜底方案)
如果修改后仍存在上下文加载冲突,可以在两个测试类上添加@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)注解,指定当前测试类执行完成后清空上下文缓存,避免不同测试类的Mock配置互相污染。
修复后参考示例(以JobTest为例,JUnit5版本)
@SpringBootTest @AutoConfigureMockMvc public class JobTest { @Autowired private WebApplicationContext applicationContext; @Autowired private MockMvc mockMvc; @MockBean private JobService jobService; private static final String URI = "/testJob/"; private final UUID jobId = UUID.fromString("d35089c0-8ca8-4a9d-8932-8464e9a0736c"); private Job mockJob; @BeforeEach void setup() { // 仅初始化测试用Mock对象,不重复构建MockMvc mockJob = new Job(); mockJob.setJobId(jobId); } @Test public void testRequestJob() throws Exception { RequestBuilder requestBuilder = MockMvcRequestBuilders.post(URI) .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.ALL) .content("testRequestString"); // 修复括号缺失问题 when(jobService.neededJob(anyString())).thenReturn(mockJob); ResultActions perform = mockMvc.perform(requestBuilder); assertEquals(HttpStatus.OK.value(), perform.andReturn().getResponse().getStatus()); perform.andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.data.jobId").exists()); } }
内容的提问来源于stack exchange,提问作者Nishant
相关产品推荐
相关产品推荐

