You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何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方法:

  1. 先引入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>
  1. 编写测试代码:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 20:08:11