如何用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
相关产品推荐
相关产品推荐

