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

Mockito/PowerMock测试失败:verify不生效及相关技术疑问

问题分析与解决方案

核心问题排查

  1. 第23行异常与verify失败的根本原因
    你的测试代码中,Thing类的fun方法默认返回新创建的ThingGrandParent实例,而非你定义的mock对象tgpp。因此when(tgpp.GpFun(anyInt())).thenReturn(tp)的配置完全无效——bLogic方法里调用的是全新的ThingGrandParent,根本不会触发你设置的mock逻辑,后续的verify自然找不到对tp的调用记录。

  2. 验证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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 13:35:40