如何在JUnit中Mock静态引用?Mock静态成员遇问题求助
解决Mock静态成员LoadPlaceDao.placeDao.PlaceMap()的测试问题
我之前做覆盖率测试时也碰到过一模一样的场景——直接Mock静态类里的成员方法确实有点棘手,尤其是像你这种静态字段调用实例方法的情况。下面给你两种可行的方案,按需选择:
方案一:用PowerMock配合Mockito解决(无需改业务代码)
默认Mockito不支持Mock静态成员,所以得借助PowerMock来搞定。先确保你的测试依赖里已经引入了PowerMock的相关包(比如powermock-module-junit4和powermock-api-mockito2),然后按步骤来:
- 给测试类加必要的注解
告诉PowerMock要处理哪个静态类:
@RunWith(PowerMockRunner.class) @PrepareForTest(LoadPlaceDao.class) public class ATest { // 测试代码写这儿 }
- Mock静态字段并指定方法返回值
我们需要先MockPlaceDao实例,再把它塞到LoadPlaceDao的静态字段里,最后指定PlaceMap()的返回值:
@Test public void testMethodA() { // 1. 创建PlaceDao的Mock对象 PlaceDao mockPlaceDao = Mockito.mock(PlaceDao.class); // 2. 设定PlaceMap()的返回值,按你的测试需求来,比如返回一个空Map或者模拟数据 Mockito.when(mockPlaceDao.PlaceMap()).thenReturn(new HashMap<>()); // 3. 让PowerMock接管LoadPlaceDao的静态逻辑,然后把Mock对象设置到静态字段里 PowerMockito.mockStatic(LoadPlaceDao.class); Whitebox.setInternalState(LoadPlaceDao.class, "placeDao", mockPlaceDao); // 4. 执行测试逻辑 A aInstance = new A(); aInstance.methodA(); // 可选:验证PlaceMap()是否被调用过 Mockito.verify(mockPlaceDao).PlaceMap(); }
这里划重点:
Whitebox.setInternalState是PowerMock的工具类,能直接修改静态类的字段值,不管它是公有还是私有。- 哪怕
LoadPlaceDao的构造方法会初始化placeDao,我们的测试代码会直接覆盖这个静态字段,所以不用担心原构造逻辑的干扰。
方案二:重构代码(更优雅的长期方案)
如果后续还有维护需求,其实可以把静态依赖改成依赖注入的方式,这样测试起来会更简单,也符合面向对象的设计原则。比如修改A类:
class A { private String place = null; private final PlaceDao placeDao; // 通过构造方法注入PlaceDao实例 public A(PlaceDao placeDao) { this.placeDao = placeDao; } public void methodA() { this.place = placeDao.PlaceMap(); // 其他业务逻辑... } }
这样测试的时候直接用Mockito就行,完全不用管静态类:
@Test public void testMethodA() { PlaceDao mockPlaceDao = Mockito.mock(PlaceDao.class); Mockito.when(mockPlaceDao.PlaceMap()).thenReturn("测试地点"); A aInstance = new A(mockPlaceDao); aInstance.methodA(); // 这里可以加断言或者验证逻辑,比如检查place是否被正确赋值 }
如果只是为了快速拿到覆盖率,方案一直接用PowerMock就能搞定;如果想让代码更易测,方案二更值得考虑。
内容的提问来源于stack exchange,提问作者Ramesh
相关产品推荐
相关产品推荐

