Mockito/PowerMock测试失败:verify不生效及相关技术疑问
问题分析与解决方案
核心问题排查
第23行异常与verify失败的根本原因
你的测试代码中,Thing类的fun方法默认返回新创建的ThingGrandParent实例,而非你定义的mock对象tgpp。因此when(tgpp.GpFun(anyInt())).thenReturn(tp)的配置完全无效——bLogic方法里调用的是全新的ThingGrandParent,根本不会触发你设置的mock逻辑,后续的verify自然找不到对tp的调用记录。验证
fetchSideThing调用的正确步骤
需要先让Thing的fun方法返回你mock的tgpp,再让tgpp的GpFun返回mock的tp,最后给tp的fetchSideThing设置返回值,才能让测试正常执行并验证方法调用。
修正后的测试代码
@RunWith(PowerMockRunner.class) @PowerMockIgnore("javax.management.*") @PrepareForTest({Thing.class, SideThing.class}) public class ThingTest { @Mock ThingParent tp; @Mock ThingGrandParent tgpp; Thing t; @Before public void setup() { // 替代过时的initMocks方法 MockitoAnnotations.openMocks(this); t = spy(new Thing()); } @Test public void test1() throws Exception { // 1. 让Thing的fun方法返回mock的tgpp doReturn(tgpp).when(t).fun(anyInt()); // 2. 让tgpp的GpFun返回mock的tp when(tgpp.GpFun(anyInt())).thenReturn(tp); // 3. 给tp的fetchSideThing设置返回值,保证assertEquals断言通过 when(tp.fetchSideThing()).thenReturn(new SideThing(4)); assertEquals(4, t.bLogic(4)); // 验证fetchSideThing被调用一次 verify(tp, times(1)).fetchSideThing(); } }
额外问题解答
1. Thing用spy还是InjectMocks的区别
- spy:是对真实
Thing对象的包装,默认执行真实方法逻辑,可选择性mock其中特定方法(比如这里的fun方法),适合需要保留大部分真实逻辑、仅mock少数方法的场景。 - InjectMocks:用于将已定义的mock对象自动注入到被测试对象的字段中,适用于被测试对象依赖其他类(通过字段注入)的场景。你的
Thing没有依赖其他类,因此用spy更合适。
2. 过时方法MockitoAnnotations.initMocks(this)的替代方案
直接替换为MockitoAnnotations.openMocks(this),这是Mockito官方推荐的替代方法,用于初始化测试类中的mock和spy对象。
原失败信息
Wanted but not invoked: tp.fetchSideThing(); -> at com.amazon.configurationeditor.store.ThingTest.test1(ThingTest.java:62) Actually, there were zero interactions with this mock. Wanted but not invoked: tp.fetchSideThing(); -> at com.amazon.configurationeditor.store.ThingTest.test1(ThingTest.java:62) Actually, there were zero interactions with this mock. at com.amazon.configurationeditor.store.ThingTest.test1(ThingTest.java:62) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68) at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:326) at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:89) at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:97) at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:310) at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:131) at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.access$100(PowerMockJUnit47RunnerDelegateImpl.java:59) at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner$TestExecutorStatement.evaluate(PowerMockJUnit47RunnerDelegateImpl.java:147) at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.evaluateStatement(PowerMockJUnit47RunnerDelegateImpl.java:107) at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:82) at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:298) at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:87) at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:50) at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:218) at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:160) at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:134) at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34) at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44) at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:136) at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:117) at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:57) at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69) at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38) at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11) at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35) at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235) at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
内容的提问来源于stack exchange,提问作者Pricey
相关产品推荐
相关产品推荐

