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

Java PanacheQuery测试抛空指针异常,求排查Mock配置问题

问题

手动测试使用PanacheQuery的findByNameAndTag函数时运行正常,但编写测试用例执行时抛出空指针异常,异常出现在.firstResultOptional()调用处。

测试代码如下:

void testFindByNameAndTag() throws ApplicationException {
  final ImageRepository repo = mock(ImageRepository.class);
  final PanacheQuery<ImageBE> panacheQuery = mock(PanacheQuery.class);

  when(repo.findByNameAndTag(anyString(), anyString())).thenCallRealMethod();
  when(repo.find(anyString(), anyString())).thenReturn(panacheQuery);
  when(panacheQuery.firstResultOptional()).thenReturn(Optional.of(new ImageBE()));

  final ImageBE result = repo.findByNameAndTag("name", "tag");
  assertNotNull(result);
}

ImageRepository中的findByNameAndTag函数实现:

@ApplicationScoped
public class ImageRepository implements PanacheRepositoryBase<ImageBE, Long> {

  private static final Log LOG = LogFactory.getLog(ImageRepository.class);

  public ImageBE findByNameAndTag(String name, String tag) throws ApplicationException {
    return find("name = ?1 and tag = ?2", name, tag)
            .firstResultOptional()
            .orElseThrow(
                    () ->
                            new ApplicationException(SOME_ERROR_CODE, SOME_ERROR_MESSAGE));
  }

}

请问是不是Mock或when的用法存在错误?


问题原因及解决方案

问题核心在于Mock对象的方法调用上下文不匹配:

  • 用mock(ImageRepository.class)创建的是完全Mock的对象,当通过thenCallRealMethod()执行findByNameAndTag的真实逻辑时,方法内部调用的find并不会使用你预先Mock的返回值。因为Mock对象的所有未显式指定的方法默认返回null,而你对repo.find的Mock设置,无法作用于真实方法内部的调用。

修正后的测试代码

改用Spy包装ImageRepository实例,既能保留真实方法逻辑,又能Mock父类的find方法:

void testFindByNameAndTag() throws ApplicationException {
  // 使用Spy创建实例,保留真实方法的执行逻辑
  final ImageRepository repo = spy(new ImageRepository());
  final PanacheQuery<ImageBE> panacheQuery = mock(PanacheQuery.class);

  // 用doReturn避免触发真实find方法调用
  doReturn(panacheQuery).when(repo).find(anyString(), anyString());
  when(panacheQuery.firstResultOptional()).thenReturn(Optional.of(new ImageBE()));

  final ImageBE result = repo.findByNameAndTag("name", "tag");
  assertNotNull(result);
}

关键说明

  • Mock会完全替换原对象的所有行为,仅显式指定的方法有自定义逻辑,其余默认返回null,不适合需要保留部分真实逻辑的场景。
  • Spy优先执行真实方法,仅被显式Mock的方法会使用自定义行为,符合当前需要保留findByNameAndTag真实逻辑、Mock父类find方法的需求。
  • 必须用doReturn(...).when(repo).find(...)而非when(repo.find(...)).thenReturn(...),后者会触发真实的find方法调用,而Spy的真实find方法因缺少运行时上下文会抛出异常。

内容的提问来源于stack exchange,提问作者Karlito Brigante

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 18:20:31