You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用@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());
}

问题原因及修复方案

核心问题

  1. @DataJpaTest默认不支持MongoDB:@DataJpaTest是专门为JPA(PostgreSQL这类关系型数据库)设计的测试注解,默认不会加载MongoDB的自动配置,导致你的MongoRepository相关bean无法被正确处理,mock对象自然无法注入。
  2. @InjectMocks与@Autowired冲突:同时用这两个注解标注UpdateScheduler,会导致Spring注入的真实实例和Mockito手动注入的实例冲突,最终服务用的不是你mock的EventRepository。
  3. 多余的手动配置:手动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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 21:57:51