如何Mock Java私有方法中创建的ObjectNeeded2Mock以测试公共方法?
如何Mock私有方法中直接创建的ObjectNeeded2Mock对象
方案一:用PowerMock拦截构造方法(不用改原代码)
因为原代码里ObjectNeeded2Mock是在私有方法里直接new出来的,常规Mockito搞不定这种硬编码的对象创建,得用PowerMock来拦截构造方法:
- 先引入PowerMock的依赖(比如JUnit4环境下,需要
powermock-module-junit4和powermock-api-mockito2这两个包) - 测试类上加两个注解:
@RunWith(PowerMockRunner.class) @PrepareForTest(parentClass.class) // 指定要处理的类,因为它里面new了目标对象 - 测试方法里这么写:
@Test public void testMethod1() throws Exception { // 先创建ObjectNeeded2Mock的mock实例 ObjectNeeded2Mock mockObj = Mockito.mock(ObjectNeeded2Mock.class); // 拦截parentClass里new ObjectNeeded2Mock()的操作,返回我们的mock对象 PowerMockito.whenNew(ObjectNeeded2Mock.class).withNoArguments().thenReturn(mockObj); // 给mock对象设置预期行为,比如调用某个方法返回指定值 Mockito.when(mockObj.someMethod()).thenReturn("你要的结果"); // 实例化parentClass并调用方法 parentClass parent = new parentClass(); String result = parent.method1("测试参数"); // 验证结果和mock对象的调用情况 Assert.assertEquals("预期返回值", result); Mockito.verify(mockObj).someMethod(); }
注意:这种方法适合没法改原代码的场景,但PowerMock会修改类加载机制,可能带来一些额外问题,比如和其他测试框架的兼容性。
方案二:重构原代码(更推荐,测试友好)
硬编码new对象本身就不利于测试,最好的办法是把对象创建的逻辑抽出来,让依赖可以注入:
修改原代码:
给parentClass加一个带参数的构造方法,用来传入对象的创建逻辑,同时保留原无参构造保证兼容性:
class parentClass { private final Supplier<ObjectNeeded2Mock> objCreator; // 原无参构造,保持原有功能不变 public parentClass() { this(() -> new ObjectNeeded2Mock()); } // 测试用的构造方法,传入自定义的对象创建逻辑 public parentClass(Supplier<ObjectNeeded2Mock> objCreator) { this.objCreator = objCreator; } public String method1(String... arguments){ Obj obj1 = privateMethod(arguments[0]); return "处理结果"; } private Obj privateMethod(String argument){ // 用Supplier创建对象,而不是直接new ObjectNeeded2Mock obj = objCreator.get(); // 原来的业务逻辑 return new Obj(); } }
测试代码:
这时候用常规Mockito就能搞定,不用额外框架:
@Test public void testMethod1() { // 创建mock对象 ObjectNeeded2Mock mockObj = Mockito.mock(ObjectNeeded2Mock.class); // 设置mock的预期行为 Mockito.when(mockObj.someMethod()).thenReturn("预期值"); // 实例化parentClass时,传入返回mock对象的Supplier parentClass parent = new parentClass(() -> mockObj); // 调用方法并获取结果 String result = parent.method1("测试参数"); // 验证结果和mock的调用 Assert.assertEquals("预期返回结果", result); Mockito.verify(mockObj).someMethod(); }
这种方式让代码结构更清晰,符合依赖倒置原则,后续维护起来也更方便,是长期来看更优的选择。
内容的提问来源于stack exchange,提问作者Jacobo Geada
相关产品推荐
相关产品推荐

