如何使用Mockito为抽象类中的依赖对象实现mock(非@InjectMock方式)
问题根因
你当前的写法存在两个问题导致mamApiDao注入失败:
@InjectMocks无法对通过Mockito.mock手动生成的代理对象执行依赖注入,你声明的@InjectMocks注解在这里完全不生效。- 你生成抽象类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
相关产品推荐
相关产品推荐

