Java8+Maven3.9下PowerMock验证私有void方法遇NoSuchMethodError
问题:PowerMock验证私有void方法调用时出现NoSuchMethodError
环境与需求
- Java 8
- Maven 3.9
- 需求:验证私有void方法
logEvent的调用情况,使用PowerMock实现
现有配置与代码
pom.xml依赖
<properties> <powermock.version>2.0.2</powermock.version> </properties> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <scope>test</scope> <version>4.4.0</version> </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-inline</artifactId> <scope>test</scope> <version>4.4.0</version> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> <version>${powermock.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-mockito2</artifactId> <version>${powermock.version}</version> <scope>test</scope> </dependency>
服务类MyService
public class MyService { private String data; public MyService(String data) { this.data = data; } public void processData() { // Some processing logic String message = "Processing data: " + data; logEvent(message); // More processing logic } private void logEvent(String message) { // In a real scenario, this would log the event System.out.println("Logging: " + message); } }
测试类MyServiceTest
import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import static org.mockito.Mockito.times; import static org.powermock.api.mockito.PowerMockito.verifyPrivate; @RunWith(PowerMockRunner.class) @PrepareForTest(MyService.class) // Prepare MyService for bytecode manipulation public class MyServiceTest { @Test public void testProcessData_shouldCallLogEvent() throws Exception { // Arrange String testData = "sampleData"; MyService service = new MyService(testData); MyService spyService = PowerMockito.spy(service); // Create a spy to track private method calls // Act spyService.processData(); // HERE ERROR!!! // Assert // Verify that the private method 'logEvent' was called exactly once verifyPrivate(spyService, times(1)).invoke("logEvent", "Processing data: sampleData"); } }
错误信息
java.lang.NoSuchMethodError: org.mockito.invocation.InvocationFactory.createInvocation(Ljava/lang/Object;Lorg/mockito/mock/MockCreationSettings;Ljava/lang/reflect/Method;Ljava/util/concurrent/Callable;[Ljava/lang/Object;)Lorg/mockito/invocation/Invocation; at com.myproject.handler.MyService.processData(MyService.java:15) at com.myproject.handler.MyService.processData(MyService.java:14) at com.myproject.handler.MyServiceTest.testProcessData_shouldCallLogEvent(MyServiceTest.java:26) at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68) at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:89) at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:97) at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:87) at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:50)
问题原因
PowerMock 2.0.2与Mockito 4.4.0存在版本兼容性问题。PowerMock 2.x系列仅支持Mockito 2.x到3.x版本,无法适配Mockito 4.x的API变更,导致反射调用时找不到对应方法。
解决方案
1. 调整依赖版本
将Mockito版本降级到PowerMock 2.0.2支持的最高版本(Mockito 3.12.4),同时移除mockito-inline依赖(PowerMock的字节码操作已覆盖其功能)。修改后的pom.xml依赖如下:
<properties> <powermock.version>2.0.2</powermock.version> <mockito.version>3.12.4</mockito.version> </properties> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <scope>test</scope> <version>${mockito.version}</version> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> <version>${powermock.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-mockito2</artifactId> <version>${powermock.version}</version> <scope>test</scope> </dependency>
2. 验证测试代码
无需修改原有测试逻辑,调整依赖后直接运行测试即可。PowerMock将正常跟踪私有方法调用并完成验证。
结果
调整依赖后,testProcessData_shouldCallLogEvent测试将成功通过,确认私有方法logEvent被调用了1次。
内容的提问来源于stack exchange,提问作者Alexei
相关产品推荐
相关产品推荐

