如何Mock外部依赖中父类的protected方法?
测试调用外部父类protected方法的异常场景
我正尝试测试一个方法,该方法内部会调用来自外部依赖父类的protected方法。以下是简化示例:
示例代码
外部依赖父类Parent
public class Parent { protected void parentAction() { System.out.println("Parent action"); } }
自定义子类Child
public class Child extends Parent { private final Runnable backupAction; private final Runnable normalAction; public Child(Runnable backupAction, Runnable normalAction) { this.backupAction = backupAction; this.normalAction = normalAction; } public void childAction() { try { super.parentAction(); } catch (Exception exc) { this.backupAction.run(); return; } this.normalAction.run(); } }
测试需求
我希望测试当parentAction抛出异常时,backupAction被调用而normalAction不被调用,这可通过verify()实现,但前提是要Mock super.parentAction()使其抛出异常。常规通过测试目录创建同名包覆盖父类的方案不适用于我的场景,因为父类是外部依赖,我无法访问其包。
解决方案
方案1:创建匿名子类覆盖父类方法(无额外依赖)
利用Java子类可覆盖父类protected方法的特性,在测试中创建Child的匿名子类,重写parentAction方法使其抛出异常,无需依赖Mock框架之外的工具:
import org.junit.Test; import static org.mockito.Mockito.*; public class ChildTest { @Test public void testChildActionWhenParentThrowsException() { // Mock传入的Runnable实例 Runnable mockBackup = mock(Runnable.class); Runnable mockNormal = mock(Runnable.class); // 创建匿名子类,覆盖parentAction使其抛出异常 Child testChild = new Child(mockBackup, mockNormal) { @Override protected void parentAction() { throw new RuntimeException("模拟父类方法抛出异常"); } }; // 调用待测试方法 testChild.childAction(); // 验证backupAction被调用,normalAction未被调用 verify(mockBackup).run(); verify(mockNormal, never()).run(); } }
方案2:使用PowerMockito Mock父类方法(需引入PowerMock依赖)
如果场景更复杂(比如无法覆盖父类方法),可以使用PowerMockito来直接Mock父类的protected方法:
- 先引入PowerMock相关依赖(以Maven为例):
<dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> <version>2.0.9</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-mockito2</artifactId> <version>2.0.9</version> <scope>test</scope> </dependency>
- 编写测试代码:
import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import static org.mockito.Mockito.*; @RunWith(PowerMockRunner.class) @PrepareForTest(Child.class) public class ChildTestWithPowerMock { @Test public void testChildActionWhenParentThrowsException() { Runnable mockBackup = mock(Runnable.class); Runnable mockNormal = mock(Runnable.class); Child child = PowerMockito.spy(new Child(mockBackup, mockNormal)); // Stub父类的parentAction方法,使其抛出异常 PowerMockito.doThrow(new RuntimeException()).when(child, "parentAction"); child.childAction(); verify(mockBackup).run(); verify(mockNormal, never()).run(); } }
内容的提问来源于stack exchange,提问作者Chaosfire
相关产品推荐
相关产品推荐

