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

如何用Mockito/PowerMock Mock私有ExampleController测试ExampleMemberClass

用Mockito/PowerMock模拟依赖方法实现单元测试

要测试ExampleMemberClass的getMemberDownloadURL方法,同时避免执行实际的API请求,可以通过Mockito或PowerMock来模拟ExampleController的getDownloadURL方法响应,下面分两种场景给出实现方案:

方案一:通过依赖注入降低耦合(推荐)

原代码里ExampleMemberClass直接在内部new实例,导致依赖耦合过紧,不利于测试。可以修改类的构造逻辑,通过构造函数注入ExampleController依赖:

修改后的ExampleMemberClass代码:

public class ExampleMemberClass {
    private final ExampleController controller;

    // 构造函数注入依赖
    public ExampleMemberClass(ExampleController controller) {
        this.controller = controller;
    }

    public String getMemberDownloadURL(Object o, String c) {
        // 原有业务逻辑,生成变量a、b
        String a = "业务逻辑生成的a值";
        String b = "业务逻辑生成的b值";
        String responseURL = controller.getDownloadURL(a, b, c);
        // 后续业务逻辑处理
        return responseURL;
    }
}

对应的Mockito测试代码:

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
public class ExampleMemberClassTest {

    // 模拟ExampleController实例
    @Mock
    private ExampleController mockController;

    // 将mock实例注入到待测试类中
    @InjectMocks
    private ExampleMemberClass memberClass;

    @Test
    public void testGetMemberDownloadURL() {
        // 测试参数
        Object testObj = new Object();
        String testC = "test-param-c";
        String mockDownloadUrl = "https://mock.example.com/download";

        // 配置mock方法的返回值,匹配任意字符串参数
        when(mockController.getDownloadURL(anyString(), anyString(), anyString()))
                .thenReturn(mockDownloadUrl);

        // 调用待测试方法
        String result = memberClass.getMemberDownloadURL(testObj, testC);

        // 验证结果符合预期
        assertEquals(mockDownloadUrl, result);

        // 如果需要验证方法调用次数或特定参数匹配,可添加如下代码:
        // verify(mockController, times(1)).getDownloadURL(anyString(), anyString(), eq(testC));
    }
}

方案二:不修改原代码,用PowerMock拦截内部实例化

如果没法修改ExampleMemberClass的原有代码,可以用PowerMock拦截内部new ExampleController()的操作,返回模拟实例:

首先需要引入PowerMock的相关依赖(比如适配JUnit5的PowerMock依赖),然后编写测试代码:

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit5.PowerMockExtension;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;

@ExtendWith(PowerMockExtension.class)
// 指定需要拦截实例化操作的类
@PrepareForTest(ExampleMemberClass.class)
public class ExampleMemberClassPowerMockTest {

    @Test
    public void testGetMemberDownloadURL() throws Exception {
        // 创建模拟的ExampleController实例
        ExampleController mockController = PowerMockito.mock(ExampleController.class);
        String mockResponse = "https://mock.example.com/download";

        // 拦截ExampleMemberClass内部new ExampleController()的操作,返回mock实例
        PowerMockito.whenNew(ExampleController.class).withNoArguments().thenReturn(mockController);

        // 配置mock方法的返回值
        when(mockController.getDownloadURL(anyString(), anyString(), anyString()))
                .thenReturn(mockResponse);

        // 实例化待测试类
        ExampleMemberClass memberClass = new ExampleMemberClass();
        // 调用测试方法
        String result = memberClass.getMemberDownloadURL(new Object(), "test-param-c");

        // 验证结果
        assertEquals(mockResponse, result);
    }
}

注意事项

  • 方案一的依赖注入方式更符合代码设计原则,耦合度低,测试逻辑更清晰,优先推荐使用。
  • 方案二的PowerMock方式需要额外依赖,且会绕过Java的常规类加载机制,仅在无法修改原代码的场景下使用。

内容的提问来源于stack exchange,提问作者Sotos Hadjipanayi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 18:15:49