使用@DataJpaTest时@MockBean未生效问题排查
问题:@DataJpaTest中MockBean未生效,@SpringBootTest正常
环境信息
2个数据源 - PostgreSQL 和 MongoDB JDK 17 Spring Boot 3.1.1 JUnit 4
使用@DataJpaTest做测试时,UpdateScheduler服务调用EventRepository的findByIdentifierFlapIn方法时,@MockBean创建的mock对象没返回预期结果,但切换到@SpringBootTest后所有功能都正常。
相关代码片段
Mock配置
@MockBean EventRepository eventRepository; when(this.eventRepository.findByIdentifierFlapIn(any())).thenReturn(mock);
EventRepository定义
@Repository public interface EventRepository extends MongoRepository<Flap, String> { List<Flap> findByIdentifierFlapIn(List<String> identifierFlap); }
测试类(注释部分为出问题的配置)
@RunWith(SpringRunner.class) //@DataJpaTest //@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) //@ComponentScan(basePackages = {"com.X.resultado", "com.X.updates"}) //@Import({ // Configuracao.class, // EventRepository.class //}) @SpringBootTest @TestPropertySource("classpath:application-test.properties") public class TestUpdater { @Autowired ResultadoRepository resultadoRepository; @MockBean EventRepository eventRepository; @InjectMocks @Autowired UpdateScheduler updateScheduler; (...) @Before public void setUp() { closeable = MockitoAnnotations.openMocks(this); resultadoBaronezaList = List.of( new ResultBar(), new ResultBar(), new ResultBar() ); resultadoBaronezaList.get(0).setId(1L); resultadoBaronezaList.get(0).setIdentifierFlap("identifier1"); (...) }
UpdateScheduler服务类
@Service public class UpdateScheduler { private final Logger logger = getLogger(this.getClass()); private final ResultadoRepository resultadoRepository; private final EventRepository eventRepository; @Autowired public UpdateScheduler(ResultadoRepository resultadoRepository, EventRepository eventRepository) { this.resultadoRepository = resultadoRepository; this.eventRepository = eventRepository; } @Scheduled(fixedRateString = "${bar.timeUpdate}") public void verificaAtualizacoes() { List<ResultadoBar> ativos = resultadoRepository.findAllByType("1"); List<String> identifierFlapList = ativos.stream().map(ResultadoBar::getIdentifierFlap).toList(); //**此处mock未生效** List<Flap> flapsModificados = eventRepository.findByIdentifierFlapIn(identifierFlapList); List<ResultadoBar> resultadoBarList = new ArrayList<>(); (...) }
测试方法
@Test public void validaClearForcado(){ resultadoRepository.saveAll(resultadoBarList); List<Flap> mock = new ArrayList<>(flapList); mock.get(0).setLastSeenFlap("Feb 27, 2024 3:00:00 PM"); when(this.eventRepository.findByIdentifierFlapIn(any())).thenReturn(mock); updateScheduler.verificaAtualizacoes(); var r0 = resultadoRepository.findById(1L).get(); assertEquals(LocalDateTime.of(2024,2,27,15,0,0), r0.getDataUltimoFlap()); assertTrue(r0.isClearForcado()); }
问题原因及修复方案
核心问题
- @DataJpaTest默认不支持MongoDB:
@DataJpaTest是专门为JPA(PostgreSQL这类关系型数据库)设计的测试注解,默认不会加载MongoDB的自动配置,导致你的MongoRepository相关bean无法被正确处理,mock对象自然无法注入。 - @InjectMocks与@Autowired冲突:同时用这两个注解标注UpdateScheduler,会导致Spring注入的真实实例和Mockito手动注入的实例冲突,最终服务用的不是你mock的EventRepository。
- 多余的手动配置:手动
Import EventRepository是没必要的,@MockBean会自动替换容器中的真实实例;另外MockitoAnnotations.openMocks(this)在@RunWith(SpringRunner.class)下是冗余的,Spring已经集成了Mockito支持。
修复后的测试类配置
@RunWith(SpringRunner.class) @DataJpaTest @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) // 新增MongoDB测试自动配置 @AutoConfigureMongoDb @ComponentScan(basePackages = {"com.X.resultado", "com.X.updates"}) @Import(Configuracao.class) @TestPropertySource("classpath:application-test.properties") public class TestUpdater { @Autowired ResultadoRepository resultadoRepository; @MockBean EventRepository eventRepository; // 只保留@Autowired,移除@InjectMocks @Autowired UpdateScheduler updateScheduler; @Before public void setUp() { // 移除MockitoAnnotations.openMocks(this) resultadoBaronezaList = List.of( new ResultBar(), new ResultBar(), new ResultBar() ); resultadoBaronezaList.get(0).setId(1L); resultadoBaronezaList.get(0).setIdentifierFlap("identifier1"); (...) } // 测试方法不变 }
额外注意点
- 确保
application-test.properties中PostgreSQL的配置正确,因为你设置了replace = NONE,会使用真实数据库而不是内存库。 - 确认
ComponentScan的包路径包含UpdateScheduler所在的包,保证服务能被Spring扫描到。
内容的提问来源于stack exchange,提问作者Goldman7911
相关产品推荐
相关产品推荐

