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

Mockito模拟变量仍为null引发NullPointerException问题排查

问题原因排查及解决方案

核心问题1:Mock对象无法初始化依赖且不执行真实逻辑

你用Mockito.mock(ShowService.class)创建的是Mock代理对象,这类对象不会初始化原类的私有字段(包括blogCoreSolrClient),也不会执行原类的真实方法逻辑——这直接导致调用findShow时,blogCoreSolrClient为null,抛出空指针异常。

核心问题2:错误调用实例方法(误当成静态方法)

findShow是ShowService的protected实例方法,测试代码里写成ShowService.findShow(...)属于语法错误(原方法并非静态),即便编译通过,也无法正确触发目标逻辑。

核心问题3:未针对真实方法执行场景配置Mock

要测试findShow的真实逻辑,不能直接Mock整个ShowService,需要用Spy对象或手动注入依赖的方式保留原类逻辑。


修正后的测试方案

方案1:使用Mockito Spy注入依赖并执行真实方法

Spy对象会保留原类的真实逻辑,同时允许Mock指定依赖:

public class ShowServiceTest {

    @Mock
    private SolrClient blogCoreSolrClient;
    @Mock
    private QueryResponse queryResponse;

    // 创建ShowService的Spy对象(抽象类需用匿名子类实例化)
    @Spy
    private ShowService showService = new ShowService() {};

    @BeforeEach
    void setUp() {
        // 初始化Mock对象
        MockitoAnnotations.openMocks(this);
        // 反射注入私有字段blogCoreSolrClient
        ReflectionTestUtils.setField(showService, "blogCoreSolrClient", blogCoreSolrClient);
    }

    @Test
    void findShowTest() throws SolrServerException, IOException {
        // 准备测试数据
        ShowService.SyndicatedShow mockShow = new ShowService.SyndicatedShow();
        mockShow.pathValue = "shows/test/";
        mockShow.showId = 1234;

        // Stub SolrClient的query方法,返回预设响应
        when(blogCoreSolrClient.query(any(SolrQuery.class))).thenReturn(queryResponse);
        // Stub QueryResponse的getBeans方法,返回测试数据
        when(queryResponse.getBeans(ShowService.SyndicatedShow.class)).thenReturn(List.of(mockShow));

        // 调用真实的findShow方法
        ShowService.SyndicatedShow result = showService.findShow(ClientRegion.US, TargetLocale.EN_US, 1234);

        // 验证结果
        assertThat(result.pathValue).isEqualTo("shows/test/");
        // 验证SolrClient的query方法被调用一次
        verify(blogCoreSolrClient, times(1)).query(any(SolrQuery.class));
    }
}

方案2:手动创建子类并注入依赖

如果不想用Spy,可手动实现ShowService的子类,再注入依赖:

public class ShowServiceTest {

    private SolrClient blogCoreSolrClient;
    private QueryResponse queryResponse;
    private ShowService testService;

    @BeforeEach
    void setUp() {
        // 初始化Mock对象
        blogCoreSolrClient = Mockito.mock(SolrClient.class);
        queryResponse = Mockito.mock(QueryResponse.class);
        // 创建ShowService的实现子类
        testService = new ShowService() {};
        // 反射注入私有字段
        ReflectionTestUtils.setField(testService, "blogCoreSolrClient", blogCoreSolrClient);
    }

    @Test
    void findShowTest() throws SolrServerException, IOException {
        // 准备测试数据和Stub逻辑
        ShowService.SyndicatedShow mockShow = new ShowService.SyndicatedShow();
        mockShow.pathValue = "shows/test/";
        mockShow.showId = 1234;

        when(blogCoreSolrClient.query(any(SolrQuery.class))).thenReturn(queryResponse);
        when(queryResponse.getBeans(ShowService.SyndicatedShow.class)).thenReturn(List.of(mockShow));

        // 调用方法并验证结果
        ShowService.SyndicatedShow result = testService.findShow(ClientRegion.US, TargetLocale.EN_US, 1234);
        assertThat(result.pathValue).isEqualTo("shows/test/");
    }
}

额外注意事项

  1. 原代码中findShow返回Show类型,但内部调用response.getBeans(Show.class),而定义的内部类是SyndicatedShow,存在类型不匹配问题,需确认Show与SyndicatedShow的关系。
  2. SolrClient.query会抛出SolrServerException和IOException,测试需处理这些异常。
  3. ReflectionTestUtils需引入Spring Test依赖,无Spring环境时可改用Java原生反射API设置字段值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 07:36:17