【问题标题】:PowerMockito.whenNew is Working with Reference not working with ObjectPowerMockito.whenNew 正在使用参考而不是使用对象
【发布时间】:2025-11-21 09:35:01
【问题描述】:

我试图理解以下场景的测试,其中应该模拟地图的第一次创建并且不应该模拟第二次实例的创建,并且我已经按照以下方式编写了在一个场景中工作而在以后的场景中不工作的方式,

public class A {

  public void test(){
    Map<String,String> map = new HashMap<String, String>();
    Map<String,String> map1 = new HashMap<String, String>();
    System.out.println(map);
    System.out.println(map1);
  }
}

按预期工作的第一种编写测试的方法

@RunWith(PowerMockRunner.class)
@PrepareForTest(A.class)
public class ATest {

    @Test
    public void test() throws  Exception{
        HashMap<String,String> map = PowerMockito.mock(HashMap.class);
        HashMap<String,String> hashMap = new HashMap<String, String>();
        PowerMockito.whenNew(HashMap.class).withNoArguments().thenReturn(map,hashMap);
        A a = new A();
        a.test();
    }


}

我直接传递 new HashMap() 的第二种方式,抛出异常,

@RunWith(PowerMockRunner.class)
@PrepareForTest(A.class)
public class ATest {

    @Test
    public void test() throws  Exception{
        HashMap<String,String> map = PowerMockito.mock(HashMap.class);
        PowerMockito.whenNew(HashMap.class).withNoArguments().thenReturn(map,new HashMap<String,String>());
        A a = new A();
        a.test();
    }


}

谁能告诉我为什么当我直接通过 HashMap 时它不起作用.....?

【问题讨论】:

  • 在使用方法链时会发生同样的情况吗?即.thenReturn(map).thenReturn(new HashMap&lt;String,String&gt;())
  • @Nkosi 方法链接所有实例都分配了模拟 HashMap,链接/添加第二个 thenReturn 没有效果
  • 抛出了什么异常。
  • @Nkosi org.mockito.exceptions.misusing.UnfinishedStubbingException:在此处检测到未完成的存根:-> 在 ATest.test(ATest.java:23) 例如thenReturn() 可能会丢失。正确的存根示例:when(mock.isOk()).thenReturn(true); when(mock.isOk()).thenThrow(异常); doThrow(exception).when(mock).someVoidMethod();提示:
  • @Nkosi 认为我创建的 Mock 不是最终的,但它仍在工作..,我们的变量/引用/对象不必是最终的

标签: powermock


【解决方案1】:

在您的第二个测试中,您违反了 Mockito 验证系统施加的顺序约束。 Mockito 会验证您是否正确使用了它的方法,如果没有,则抛出 UnfinishedStubbingException

PowerMockito.whenNew(HashMap.class).withNoArguments().thenReturn(map,new HashMap<String,String>());

首先,执行对whenNew() 的调用。这会导致 Mockito 拦截所有对 HashMap::new 的后续调用。但是,您实际上还没有告诉它要返回什么(thenReturn() 部分尚未运行),因此现在调用 HashMap 构造函数是无效的。如果这样做,您将遇到异常。

现在让我们看看thenReturn() 部分。完成后,您可以再次安全地调用HashMap::new - Mockito 会知道要返回什么。但在调用thenReturn() 之前,必须解析其所有参数。这会导致HashMap 构造函数被过早调用——因此是异常。当它被调用时,你已经让 Mockito 处于关于HashMap::new 的无效中间状态。所以它抛出一个异常。

相比之下,您的第一个测试很好,因为您在 Mockito 被告知拦截呼叫之前实例化了 HashMap

【讨论】: