Java Mockito NumberFormat在when()方法中模拟空指针

Java Mockito NumberFormat在when()方法中模拟空指针,java,junit,mockito,Java,Junit,Mockito,所以我有一段代码,它会抛出一个NullPointerException NumberFormat formatterFake=mock(NumberFormat.class); 当(formatterFake.format(1)),然后返回(“1”); 问题是我在when()方法中遇到异常: 我还试着模仿混凝土课堂,得到了同样的结果 NumberFormat formatterFake=mock(DecimalFormat.class); 我对莫基托有点陌生,任何帮助都是很有必要的。提前谢谢

所以我有一段代码,它会抛出一个NullPointerException

NumberFormat formatterFake=mock(NumberFormat.class);
当(formatterFake.format(1)),然后返回(“1”);
问题是我在when()方法中遇到异常:

我还试着模仿混凝土课堂,得到了同样的结果

NumberFormat formatterFake=mock(DecimalFormat.class);
我对莫基托有点陌生,任何帮助都是很有必要的。提前谢谢。

发生了什么事 好的,为了在mock上存根一个方法,您在这里做了所有的事情

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();
    }
您模拟的format方法实际上是调用另一个format方法:
NumberFormat\format(long、StringBuffer、FieldPosition)
,它位于同一个抽象类中。然后,它返回调用
toString()
的结果,调用的结果是调用的结果。这是一个最终的方法,Mockito无法将其存根

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

when(formatterFake.format(1))
实际上,您正在调用抽象
NumberFormat
类中实现的
format
方法的第一个重载

format
的第一个重载的最终实现调用第二个
format
方法。第二种
格式是
NumberFormat
中的一种抽象方法。因此,没有可调用的实现

没问题,我们正在和一个模拟人合作。Mockito为mock中每个未实现的方法提供一个默认存根

因此,当尝试存根对
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将允许直接模拟最终格式方法。

您需要使用它来模拟最终格式方法


我不知道为什么需要在
NumberFormat
类上模拟最后一个方法,这是一种测试气味。请同时发布您的测试。

格式方法是最终的。Mockito无法覆盖它。谢谢,这很有效。不过,正如您所说,这有点棘手,因为我实际上是在嘲笑我实际调用的其他方法。这对我来说有点道理。我认为模拟的整个想法是用一个虚拟的实现来代替实际的实现。为什么要调用原始代码?是因为format()方法实际上调用了自身的重载版本吗?@Andy还有,通常说不要模仿你不拥有的类型!关于你的问题,答案很简单,Mockito创建了一个子类,正如你所知,你不能重载最后一个方法,JVM在加载/使用类时强制执行这一点
  @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));
  }