4

所以我有这段代码给我一个 NullPointerException

NumberFormat formatterFake = mock(NumberFormat.class);  
when(formatterFake.format(1)).thenReturn("1");

问题是我在 when() 方法中遇到异常:

java.lang.NullPointerException
    at java.text.NumberFormat.format(NumberFormat.java:297)

我还尝试模拟具体的课程,给我同样的结果。

NumberFormat formatterFake = mock(DecimalFormat.class); 

我对 Mockito 有点陌生,任何帮助都会非常有用。提前致谢。

4

2 回答 2

4

发生了什么

好的,所以你在这里做所有事情是为了在模拟上存根一个方法。

NumberFormat是一个抽象类。这通常很好,因为 Mockito 可以像普通类一样模拟抽象类。问题与NumberFormat#format(long)方法的实现有关。

查看我正在使用 Oracle jdk 1.7.0 update 2 的实现的源代码,您可以看到此方法的作用:

public final String format(long number) {
        return format(number, new StringBuffer(), DontCareFieldPosition.INSTANCE).toString();
    }

您正在模拟的格式方法实际上是调用另一个格式方法:NumberFormat#format(long, StringBuffer, FieldPosition)它驻留在同一个抽象类中。然后它返回调用toString()调用结果的结果。这是一个FINAL方法,Mockito 不能存根。

当您使用 when-then 语法来存根方法时,Mockito 实际上会调用您正在存根的方法(如果它具有最终实现)。所以当你写:

when(formatterFake.format(1))

您实际上是在调用format抽象NumberFormat类中实现的方法的第一个重载。

第一次重载的最终实现format调用第二个format方法。第二个format NumberFormat. 所以没有实现调用。

没问题,我们正在使用模拟。Mockito 为 mock 中每个未实现的方法提供一个 Default Stubbing。 默认情况下,对于所有返回值的方法,mock 返回 null、空集合或适当的原始/原始包装器值(例如:0、false、...对于 int/Integer、boolean/Boolean、...)。

因此,当尝试对对 的调用进行存根时NumberFormat#format(long),因为它有一个实现,您最终会调用NumberFormat#format(long, StringBuffer, FieldPosition)其返回的默认存根null,然后是.toString()-ed 并且您的 NPE 有原因。

解决方案

通常你会模拟一个接口,而不是直接模拟一个类,这将完全避免此类问题的可能性,因为没有最终的任何东西。但是,由于这里没有可模拟的接口,所以它不是一个选项。

您可以直接模拟 format 的 3-arg 重载:然后它应该允许您根据需要调用 format 的一个参数版本:

  @Test
  public void test() {
    final NumberFormat mockFormatter = mock(NumberFormat.class);

    final StringBuffer buffer = new StringBuffer("1");
    when(mockFormatter.format(anyLong(), any(StringBuffer.class), any(FieldPosition.class))).thenReturn(buffer);

    System.out.println("Result: " + mockFormatter.format(1));
  }

但是,我不确定这是最好的解决方案。也许其他人会参与进来。

编辑:

在看到 Garrett Hall 的回答后,我更明确地说,当我谈论实施时,我的意思是最终实施。

正如他所建议的,如果您愿意走这条路,PowerMock 将允许直接模拟最终格式方法。

于 2012-05-15T13:53:43.360 回答
2

您将需要使用PowerMock来模拟最终方法。

我不确定你为什么需要在NumberFormat类上模拟 final 方法,这是一种测试气味。请同时发布您的测试。

于 2012-05-15T14:46:06.793 回答