Java Mockito NumberFormat在when()方法中模拟空指针
所以我有一段代码,它会抛出一个NullPointerExceptionJava 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); 我对莫基托有点陌生,任何帮助都是很有必要的。提前谢谢
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));
}