Spring Boot集成Cucumber时@MockBean空指针异常的排查与解决
问题
使用Spring Boot 3.3.0和Cucumber 7.18.0进行测试时,尝试Mock ArtistRepository,但出现空指针异常:
java.lang.NullPointerException: Cannot invoke "com.example.sampleproject.repository.ArtistRepository.findById(Object)" because "this.artistRepository" is null
步骤定义类代码:
@SpringBootTest @ContextConfiguration(classes = {SampleProjectApplication.class, CucumberSpringConfiguration.class}) public class FindArtistByIdStepDefs { @MockBean private ArtistRepository artistRepository; private DataLoaderService dataLoaderService; private List<ArtistEntity> mockedArtists = new ArrayList<>(); private List<AlbumEntity> mockedAlbums = new ArrayList<>(); public FindArtistByIdStepDefs(DataLoaderService dataLoaderService) { this.dataLoaderService = dataLoaderService; } @Given("artists exist in the DB") public void theFollowingArtistsExistInTheDB(DataTable dataTable) { List<Map<String, String>> map = dataTable.asMaps(String.class, String.class); for (Map<String, String> row : map) { ArtistEntity artist = new ArtistEntity(); String name = row.get("name"); String description = row.get("description"); long id = Long.parseLong(row.get("id")); artist.setArtist(name); artist.setDescription(description); artist.setId(id); mockedArtists.add(artist); Mockito.when(artistRepository.findById(artist.getId())).thenReturn(Optional.of(artist)); } } }
CucumberSpring配置类:
@CucumberContextConfiguration @SpringBootTest(classes = SampleProjectApplication.class) public class CucumberSpringConfiguration { public CucumberSpringConfiguration() { System.out.println("CucumberSpringConfiguration initialized"); } }
测试运行类:
@Suite @SelectClasspathResource("features") @ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "com.example.sampleproject.steps, com.example.sampleproject.config") public class TestRunner { }
当把@CucumberContextConfiguration注解直接加到FindArtistByIdStepDefs类并移除集中配置类时,测试能正常运行,但希望保留集中式配置(因存在多个步骤定义类且计划新增更多)。需要解决:使用集中式配置时@MockBean空指针的原因?如何在保持集中式配置的同时确保MockBean正确注入?
原因分析
- 重复上下文配置冲突:步骤定义类上同时标注了
@SpringBootTest和@ContextConfiguration,而集中式配置类CucumberSpringConfiguration已经通过@CucumberContextConfiguration和@SpringBootTest声明了上下文规则。这种重复配置会导致Cucumber初始化时,无法正确识别有效的上下文配置,最终使@MockBean的注入逻辑失效。 - 步骤类实例化逻辑异常:若步骤定义类存在Spring注解但未正确关联到集中式上下文,Spring容器无法对其完成依赖注入,
@MockBean标记的字段自然无法被实例化,触发空指针。
解决方案
1. 移除步骤定义类上的Spring测试注解
删除FindArtistByIdStepDefs类上的@SpringBootTest和@ContextConfiguration注解,仅保留@MockBean和构造注入逻辑,让Cucumber完全依赖集中式配置类初始化Spring上下文:
public class FindArtistByIdStepDefs { @MockBean private ArtistRepository artistRepository; private final DataLoaderService dataLoaderService; private List<ArtistEntity> mockedArtists = new ArrayList<>(); private List<AlbumEntity> mockedAlbums = new ArrayList<>(); public FindArtistByIdStepDefs(DataLoaderService dataLoaderService) { this.dataLoaderService = dataLoaderService; } @Given("artists exist in the DB") public void theFollowingArtistsExistInTheDB(DataTable dataTable) { List<Map<String, String>> map = dataTable.asMaps(String.class, String.class); for (Map<String, String> row : map) { ArtistEntity artist = new ArtistEntity(); String name = row.get("name"); String description = row.get("description"); long id = Long.parseLong(row.get("id")); artist.setArtist(name); artist.setDescription(description); artist.setId(id); mockedArtists.add(artist); Mockito.when(artistRepository.findById(artist.getId())).thenReturn(Optional.of(artist)); } } }
2. 确认配置类被正确扫描
检查测试运行类TestRunner的GLUE_PROPERTY_NAME参数,确保已包含配置类所在包com.example.sampleproject.config,保证Cucumber能找到并使用集中式配置类。
3. 验证MockBean注入时机(可选)
若问题仍存在,可在步骤定义类中添加@PostConstruct方法验证注入状态,避免在构造阶段使用未初始化的MockBean:
@PostConstruct public void init() { Assert.notNull(artistRepository, "ArtistRepository mock should be injected"); }
内容的提问来源于stack exchange,提问作者sjs
相关产品推荐
相关产品推荐

