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

如何使用Mockito为抽象类中的依赖对象实现mock(非@InjectMock方式)

问题根因

你当前的写法存在两个问题导致mamApiDao注入失败:

  1. @InjectMocks无法对通过Mockito.mock手动生成的代理对象执行依赖注入,你声明的@InjectMocks注解在这里完全不生效。
  2. 你生成抽象类mock的方式默认调用无参构造,而你的CallbackManager只有带MamApiDao的有参构造,生成的mock实例没有给mamApiDao赋值,自然触发空指针。

解决方案

下面给出两种Mockito原生支持的方案,无需修改原有业务代码即可完成抽象类的测试覆盖:

方案一:指定构造参数生成抽象类mock(适用于Mockito 3.5及以上版本)

直接删除@InjectMocks注解,在初始化阶段手动指定构造参数创建抽象类mock实例:

import com.qvc.qq.mamapimodel.model.mamapi.OvpStatus;
import com.qvc.qq.mamapimodel.model.mamapi.response.OvpStatusResponse;
import com.qvc.qq.mammessageprocessor.dao.MamApiDao;
import com.qvc.qq.mammessageprocessor.model.CdnCallbackMessage;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

public class CallbackManagerTest {

    @Mock
    MamApiDao mamApiDao;
    
    @Mock
    CdnCallbackMessage cdnCallbackMessage;

    CallbackManager callbackManager;
    
    @BeforeEach
    void setUp() {
        MockitoAnnotations.openMocks(this);
        // 手动指定构造参数创建抽象类mock,所有未打桩的方法默认调用真实逻辑
        callbackManager = Mockito.mock(CallbackManager.class,
                Mockito.withSettings()
                        .useConstructor(mamApiDao)
                        .defaultAnswer(Mockito.CALLS_REAL_METHODS));
        // 提前给回调消息的getMediaId打桩,避免调用时触发空指针
        when(cdnCallbackMessage.getMediaId()).thenReturn("test-media-id");
    }
    
    @Test
    public void processCallbackTest() {
        when(mamApiDao.updateOvpMetadataInMam(any(), anyString(), any(), anyString())).thenReturn(new OvpStatusResponse());
        callbackManager.processCallback(cdnCallbackMessage, 1, OvpStatus.ACTIVE, "published");
        verify(mamApiDao, times(1)).updateOvpMetadataInMam(any(), anyString(), any(), anyString());
    }
}

方案二:使用极简测试子类(兼容性更好,支持所有Mockito版本)

在测试类中创建一个无额外逻辑的子类继承抽象类,即可正常使用@InjectMocks完成依赖注入:

import com.qvc.qq.mamapimodel.model.mamapi.OvpStatus;
import com.qvc.qq.mamapimodel.model.mamapi.response.OvpStatusResponse;
import com.qvc.qq.mammessageprocessor.dao.MamApiDao;
import com.qvc.qq.mammessageprocessor.manager.CallbackManager;
import com.qvc.qq.mammessageprocessor.model.CdnCallbackMessage;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

public class CallbackManagerTest {

    @Mock
    MamApiDao mamApiDao;
    
    @Mock
    CdnCallbackMessage cdnCallbackMessage;

    @InjectMocks
    TestCallbackManager callbackManager;
    
    // 极简测试子类,仅用来实例化抽象类,无任何额外业务逻辑
    static class TestCallbackManager extends CallbackManager {
        public TestCallbackManager(MamApiDao mamApiDao) {
            super(mamApiDao);
        }
    }
    
    @BeforeEach
    void setUp() {
        MockitoAnnotations.openMocks(this);
        when(cdnCallbackMessage.getMediaId()).thenReturn("test-media-id");
    }
    
    @Test
    public void processCallbackTest() {
        when(mamApiDao.updateOvpMetadataInMam(any(), anyString(), any(), anyString())).thenReturn(new OvpStatusResponse());
        callbackManager.processCallback(cdnCallbackMessage, 1, OvpStatus.ACTIVE, "published");
        verify(mamApiDao, times(1)).updateOvpMetadataInMam(any(), anyString(), any(), anyString());
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 02:54:02