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

从JMockit迁移至Mockito遇空指针与验证异常求助

问题排查与解决方案

你遇到的核心问题是Mockito的@Mock注解对象没有被正确初始化,导致timerSessionBean并不是一个真正的Mock实例,所以verify()方法抛出了"is not a mock"的异常。

为什么会出现这个问题?

Mockito的@Mock注解只是标记了需要被Mock的字段,但它不会自动完成Mock对象的创建——你需要触发Mockito的初始化逻辑,否则这些字段会保持默认的null(或者如果是类类型的话,是未被代理的原始对象),自然无法通过verify()的校验。

两种快速解决方法

方法1:使用Mockito扩展类(JUnit 5推荐)

在你的测试类上添加@ExtendWith(MockitoExtension.class)注解,它会自动帮你初始化所有标记了@Mock的字段:

import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
public class YourTestClass { // 替换成你的测试类名
    @Mock public EntityManager entityManager;
    @Mock public TimerSessionBean timerSessionBean;
    @Mock public Client client;
    // ... 其他字段和测试代码
}

方法2:手动初始化Mock对象

如果不想用扩展类,可以在@BeforeEach方法的最开头调用MockitoAnnotations.openMocks(this),手动触发Mock对象的初始化:

@BeforeEach final void beforeEach() {
    // 先初始化所有@Mock标记的对象
    MockitoAnnotations.openMocks(this);
    
    request = new Request();
    message = new Message();
    String spaceId = "SPACE_ID";
    String threadId = "THREAD_ID";
    caseSetReminder = new CaseSetReminder();
    caseSetReminder.entityManager = entityManager;
    caseSetReminder.timerSessionBean = timerSessionBean;
    // ... 后续代码
}

额外注意点

你在@BeforeEach里直接给timerSessionBean.nextReminderDate赋值的操作需要留意:如果nextReminderDate是TimerSessionBean的私有字段,直接赋值会报错;如果是公共字段,虽然能运行,但Mock对象的字段修改通常建议用when()或者doReturn()来模拟,更符合Mockito的使用规范:

// 替换直接赋值的代码
when(timerSessionBean.nextReminderDate).thenReturn(reminder.getWhen());

修改后的测试类示例(方法1)

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
public class CaseSetReminderTest {
    @Mock public EntityManager entityManager;
    @Mock public TimerSessionBean timerSessionBean;
    @Mock public Client client;
    private CaseSetReminder caseSetReminder;
    private Request request;
    private Message message;

    @BeforeEach final void beforeEach() {
        request = new Request();
        message = new Message();
        String spaceId = "SPACE_ID";
        String threadId = "THREAD_ID";
        caseSetReminder = new CaseSetReminder();
        caseSetReminder.entityManager = entityManager;
        caseSetReminder.timerSessionBean = timerSessionBean;
        ThreadM thread = new ThreadM();
        thread.setName("spaces/" + spaceId + "/thread/" + threadId + "");
        Sender sender = new Sender();
        sender.setName("MyName");
        message.setSender(sender);
        message.setThread(thread);
        Reminder reminder = new Reminder("Do Something", ZonedDateTime.now(ZoneId.of("Europe/Athens")).plusMinutes(10), "DisplayName", "Europe/Athens", spaceId, threadId);
        reminder.setReminderId(1);
        // 用Mockito的方式模拟字段值
        when(timerSessionBean.nextReminderDate).thenReturn(reminder.getWhen());
    }

    @Test void mockitoTest() throws Exception {
        final String expectedDate = "12/12/2019 12:00 athens";
        message.setText("remind me ' set next reminder Test' at " + expectedDate);
        request.setMessage(message);
        caseSetReminder.setRequest(request);
        caseSetReminder.setReminder();
        verify(timerSessionBean , times(1)).setNextReminder(any(Reminder.class), any(ZonedDateTime.class));
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 03:53:22