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/"); } }
额外注意事项
- 原代码中
findShow返回Show类型,但内部调用response.getBeans(Show.class),而定义的内部类是SyndicatedShow,存在类型不匹配问题,需确认Show与SyndicatedShow的关系。 SolrClient.query会抛出SolrServerException和IOException,测试需处理这些异常。ReflectionTestUtils需引入Spring Test依赖,无Spring环境时可改用Java原生反射API设置字段值。
内容的提问来源于stack exchange,提问作者Scalaboy
相关产品推荐
相关产品推荐

