Mockito单元测试:如何Mock链式调用的数据库查询方法?
如何Mock链式数据库调用并替换为自定义方法返回值
当然可以只Mock那串链式调用!我来给你拆解两种可行的实现方式,你可以根据自己的代码场景选择合适的:
方法一:逐层级手动Mock(推荐,更易维护)
这种方式适合链式调用层级清晰的场景,能明确控制每一步的返回值:
假设你的Manager类是被测对象,里面的checkFoo方法会调用getDaoProxy(),而DaoProxy又会返回ComptabiliteDao,最终调用getEcritureComptableByRef。你可以按以下步骤Mock:
- 先Mock链式调用中的每个依赖对象:
// Mock DaoProxy和ComptabiliteDao实例 DaoProxy mockDaoProxy = Mockito.mock(DaoProxy.class); ComptabiliteDao mockComptabiliteDao = Mockito.mock(ComptabiliteDao.class);
- 指定
Manager调用getDaoProxy()时返回Mock的DaoProxy:
Mockito.when(manager.getDaoProxy()).thenReturn(mockDaoProxy);
- 指定Mock的DaoProxy调用
getComptabiliteDao()时返回Mock的ComptabiliteDao:
Mockito.when(mockDaoProxy.getComptabiliteDao()).thenReturn(mockComptabiliteDao);
- 最后,让Mock的ComptabiliteDao调用目标方法时,返回
fooRepository.getOneByRef(foo.getRef())的结果:
// 先获取你想要替换的返回值 EcritureComptable expectedResult = fooRepository.getOneByRef(foo.getRef()); // 匹配方法参数并指定返回值 Mockito.when(mockComptabiliteDao.getEcritureComptableByRef(pEcritureComptable.getReference())) .thenReturn(expectedResult);
这样当checkFoo执行那串链式数据库调用时,就会直接返回你期望的结果,完全绕过真实的数据库操作。
方法二:用Mockito深层Stub简化配置
如果你觉得逐层级Mock太繁琐,也可以用Mockito的RETURNS_DEEP_STUBS选项,一次性Mock整个链式调用:
// 初始化Manager时指定深层Stub选项 Manager manager = Mockito.mock(Manager.class, Mockito.RETURNS_DEEP_STUBS); // 直接Mock整个链式调用的返回值 EcritureComptable expectedResult = fooRepository.getOneByRef(foo.getRef()); Mockito.when(manager.getDaoProxy().getComptabiliteDao().getEcritureComptableByRef(pEcritureComptable.getReference())) .thenReturn(expectedResult);
不过要注意,这种方式虽然简洁,但如果链式调用后续有修改,维护起来会比逐层级Mock麻烦,所以更适合简单的短链调用场景。
额外注意事项
- 如果
getDaoProxy()是静态方法(比如属于某个工具类),那你需要用Mockito 3.4+支持的mockStatic来Mock静态方法,示例代码如下:
// 使用try-with-resources自动管理静态Mock的生命周期 try (MockedStatic<DaoProxyUtil> mockedStatic = Mockito.mockStatic(DaoProxyUtil.class)) { ComptabiliteDao mockComptabiliteDao = Mockito.mock(ComptabiliteDao.class); DaoProxy mockDaoProxy = Mockito.mock(DaoProxy.class); // 指定静态方法的返回值 mockedStatic.when(DaoProxyUtil::getDaoProxy).thenReturn(mockDaoProxy); Mockito.when(mockDaoProxy.getComptabiliteDao()).thenReturn(mockComptabiliteDao); // 同样指定最终方法的返回值 EcritureComptable expectedResult = fooRepository.getOneByRef(foo.getRef()); Mockito.when(mockComptabiliteDao.getEcritureComptableByRef(pEcritureComptable.getReference())) .thenReturn(expectedResult); // 执行你的测试方法checkRG6 checkRG6(); }
- 如果
fooRepository本身也需要Mock(不想真的调用它的数据库方法),记得也要MockfooRepository.getOneByRef(...)的返回值,避免触发真实的数据库操作。 - 参数匹配要准确:如果
pEcritureComptable.getReference()是动态值,可以用Mockito.anyString()来模糊匹配,或者用更精确的匹配器(比如eq("目标引用值"))。
内容的提问来源于stack exchange,提问作者Joffrey
相关产品推荐
相关产品推荐

