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

能否Mock涉及CriteriaBuilder的无参方法?如何解决空指针异常?

问题描述

我原本以为无法Mock CriteriaBuilder是因为它仅对接PostgreSQL创建的数据库,但显然不是这个原因。现在我遇到了NullpointerException,错误出现在测试类的最后一行messageList = messageREST.getListAll(),相关代码如下:

MessageRest类

public List<Message> getListAll(){
    logger.info("Get all messages");
    return messageRepository.getAll();
}

MessageRepository类

public List<Message> getAll(){
    CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
    CriteriaQuery<Message> criteria = criteriaBuilder.createQuery(Message.class);
    criteria.from(Message.class);
    return entityManager.createQuery(criteria).getResultList();
}

MessageRestTest类

class MessageRESTTest {

    @InjectMocks
    MessageREST messageREST;

    @Mock
    private EntityManager entityManager;
    @Mock
    private MessageRepository messageRepository;

    @BeforeEach
    void Mockactivator() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    void testgetlistall()
    {
        List<Message> messageList = new ArrayList<>();
        Message message = new Message();
        messageList.add(message);
        when(messageRepository.getAll()).thenReturn(messageList);
        messageList = messageREST.getListAll(); 
    }
}
问题分析与解决

空指针触发原因

你的测试代码里已经Mock了MessageRepository,但空指针大概率是因为MessageREST类中的logger未初始化——getListAll()方法第一行就调用了logger.info(),如果logger是未赋值的成员变量,就会直接抛出空指针异常。

另外如果Mock未生效(比如MessageRepository没被正确注入到MessageREST),导致实际执行了MessageRepository的getAll()方法,而你没对entityManager.getCriteriaBuilder()等方法做Stub,也会触发空指针,但从你的测试代码看,这种可能性更低。

解决方案

  1. 修复logger空指针

    • 若使用SLF4J,可以在测试类中手动给messageREST的logger字段注入Mock实例:messageREST.logger = Mockito.mock(Logger.class);
    • 或者在MessageREST类中使用Lombok的@Slf4j注解,让logger自动初始化,避免测试时空值。
  2. 确保Mock注入生效

    • 检查MessageREST类中messageRepository的注入方式:如果是构造函数注入,确保测试类的MessageRepository Mock能被@InjectMocks正确注入;如果是字段注入,确认字段是private且有@Autowired注解。
    • 可以在测试方法末尾添加断言和验证,确认逻辑符合预期:
      assertEquals(1, messageList.size());
      verify(messageRepository, times(1)).getAll();
      
  3. 若需直接测试Repository的CriteriaBuilder逻辑
    如果后续要测试MessageRepository的getAll()方法而非Mock整个Repository,可以逐层Stub EntityManager相关依赖:

    @Test
    void testRepositoryGetAll() {
        // Mock CriteriaBuilder
        CriteriaBuilder cb = Mockito.mock(CriteriaBuilder.class);
        when(entityManager.getCriteriaBuilder()).thenReturn(cb);
        
        // Mock CriteriaQuery
        CriteriaQuery<Message> cq = Mockito.mock(CriteriaQuery.class);
        when(cb.createQuery(Message.class)).thenReturn(cq);
        
        // Mock Root
        Root<Message> root = Mockito.mock(Root.class);
        when(cq.from(Message.class)).thenReturn(root);
        
        // Mock TypedQuery
        TypedQuery<Message> typedQuery = Mockito.mock(TypedQuery.class);
        when(entityManager.createQuery(cq)).thenReturn(typedQuery);
        
        // 准备返回数据
        List<Message> mockList = new ArrayList<>();
        mockList.add(new Message());
        when(typedQuery.getResultList()).thenReturn(mockList);
        
        // 调用方法并断言
        List<Message> result = messageRepository.getAll();
        assertEquals(1, result.size());
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 02:25:38