PowerMock.whenNew失效排查:为何模拟File实例未生效?
PowerMock whenNew 不生效的原因及解决方案
核心问题分析
1. 方法执行顺序错误
你在调用目标方法createFileAndReturnIt()之后才配置whenNew,此时真实的File对象已经被创建并返回,后续的mock配置无法回溯影响这个已经存在的对象。PowerMock的whenNew需要在构造方法被调用前完成配置,才能拦截构造过程返回mock对象。
2. JUnit版本混用导致集成失败
测试类同时使用了JUnit 5的@Test注解(org.junit.jupiter.api.Test)和JUnit 4的@RunWith(PowerMockRunner.class),两者不兼容:PowerMockRunner是PowerMock为JUnit 4提供的运行器,无法识别JUnit 5的注解,导致PowerMock的字节码增强逻辑没有生效。
解决方案
方案一:改用JUnit 4适配PowerMockRunner
- 将测试类中的
import org.junit.jupiter.api.Test替换为import org.junit.Test - 调整代码执行顺序,先完成mock配置,再调用目标方法
修正后的测试类代码:
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.powermock.api.mockito.PowerMockito.whenNew; import java.io.File; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; @RunWith(PowerMockRunner.class) @PrepareForTest(TestPowerMock.class) public class TestTestPowerMock { @Test public void test() throws Exception { // 1. 创建mock File并配置行为 File mockFile = mock(File.class); when(mockFile.getTotalSpace()).thenReturn(1L); when(mockFile.getFreeSpace()).thenReturn(2L); // 2. 配置PowerMock拦截File构造方法 whenNew(File.class).withArguments(Mockito.anyString()).thenReturn(mockFile); // 3. 创建目标类实例并调用方法(此时构造调用会被拦截) TestPowerMock testPowerMock = new TestPowerMock(); File fileAndReturnIt = testPowerMock.createFileAndReturnIt(); // 验证输出 System.out.println(fileAndReturnIt.getFreeSpace()); // 输出2L } }
方案二:改用JUnit 5集成PowerMock
- 添加PowerMock JUnit 5扩展依赖(如
powermock-module-junit5) - 移除
@RunWith(PowerMockRunner.class),替换为JUnit 5的扩展注解@ExtendWith(PowerMockExtension.class) - 同样调整代码执行顺序
修正后的测试类代码:
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.powermock.api.mockito.PowerMockito.whenNew; import java.io.File; import org.junit.jupiter.api.Test; import org.mockito.Mockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit5.PowerMockExtension; import org.junit.jupiter.api.extension.ExtendWith; @ExtendWith(PowerMockExtension.class) @PrepareForTest(TestPowerMock.class) class TestTestPowerMock { @Test public void test() throws Exception { File mockFile = mock(File.class); when(mockFile.getTotalSpace()).thenReturn(1L); when(mockFile.getFreeSpace()).thenReturn(2L); whenNew(File.class).withArguments(Mockito.anyString()).thenReturn(mockFile); TestPowerMock testPowerMock = new TestPowerMock(); File fileAndReturnIt = testPowerMock.createFileAndReturnIt(); System.out.println(fileAndReturnIt.getFreeSpace()); // 输出2L } }
补充说明
@PrepareForTest(TestPowerMock.class)的配置是正确的,因为new File()的调用发生在TestPowerMock类内部,PowerMock需要修改该类的字节码才能拦截构造方法调用。
内容的提问来源于stack exchange,提问作者Omegaspard
相关产品推荐
相关产品推荐

