所以我有这段代码会抛出一个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来说是个新手,任何帮助都会非常谨慎。提前谢谢。
答案 0 :(得分: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为模拟中的每个未实现方法提供默认存根。 By default, for all methods that return value, mock returns null, an empty collection or appropriate primitive/primitive wrapper value (e.g: 0, false, ... for int/Integer, boolean/Boolean, ...).
因此,当尝试将调用存根到NumberFormat#format(long)
时,因为它有一个实现,所以最终调用NumberFormat#format(long, StringBuffer, FieldPosition)
的默认存根,返回null
,然后{{1}在那里你有原因你的NPE。
通常你会模拟一个接口,而不是直接模拟一个类,这样就完全避免了这类问题的可能性,因为没有最终的任何事情。但是,由于此处没有可用于模拟的界面,因此不能选择。
你可以直接模拟格式的3-arg重载:它应该允许你根据需要调用格式的一个参数版本:
.toString()
但是,我不确定这是最好的解决方案。也许其他人会权衡。
修改强>
在看到Garrett Hall的回答之后,我更明确地说,当我谈论实现时,我的意思是最终实现。
正如他所说,如果你愿意走这条路,PowerMock会允许直接嘲笑最终的格式方法。
答案 1 :(得分:2)
您需要使用PowerMock来模拟最终方法。
我不确定为什么你需要在NumberFormat
类上模拟最终方法,这是一种测试气味。请发布您的测试。