能否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,也会触发空指针,但从你的测试代码看,这种可能性更低。
解决方案
修复logger空指针
- 若使用SLF4J,可以在测试类中手动给
messageREST的logger字段注入Mock实例:messageREST.logger = Mockito.mock(Logger.class); - 或者在
MessageREST类中使用Lombok的@Slf4j注解,让logger自动初始化,避免测试时空值。
- 若使用SLF4J,可以在测试类中手动给
确保Mock注入生效
- 检查
MessageREST类中messageRepository的注入方式:如果是构造函数注入,确保测试类的MessageRepositoryMock能被@InjectMocks正确注入;如果是字段注入,确认字段是private且有@Autowired注解。 - 可以在测试方法末尾添加断言和验证,确认逻辑符合预期:
assertEquals(1, messageList.size()); verify(messageRepository, times(1)).getAll();
- 检查
若需直接测试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
相关产品推荐
相关产品推荐

