java - Mockito NumberFormat 在 when() 方法中模拟 NullPointer

标签 java junit mockito

所以我得到了这段抛出 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 的新手,任何帮助都会非常有用。提前致谢。

最佳答案

发生了什么

好的,所以您在这里做的所有事情都是为了在 mock 上 stub 方法。

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),它位于同一个抽象类中。然后返回对 that 调用结果调用 toString() 的结果。这是一个 FINAL 方法,Mockito 不能 stub 。

当您使用 when-then 语法对方法进行 stub 时,Mockito 实际上会调用您 stub 的方法(如果它有最终实现)。所以当你写:

when(formatterFake.format(1))

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

format 的第一个重载的最终实现调用了第二个format 方法。第二种 format NumberFormat 中的抽象方法。所以没有可调用的实现。

没问题,我们正在使用模拟。 Mockito 为模拟中的每个未实现的方法提供默认 stub 。 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) 调用 stub 时,因为它有一个实现,所以您最终会调用 NumberFormat#format(long, StringBuffer, FieldPosition) 返回 null,然后被 .toString() 编辑,这就是 NPE 的原因。

解决方案

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

您可以直接模拟 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 将允许直接模拟最终格式方法,如果您愿意走那条路的话。

关于java - Mockito NumberFormat 在 when() 方法中模拟 NullPointer,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10598898/

相关文章:

java - 模拟服务器请求

java - 如何测试传递给工厂方法构造函数的参数?

mocking - Mockito 中的@SpyBean 和@MockBean 有什么区别?

java - Mockito @Mock 不使用构造函数注入(inject)正确注入(inject)命名模拟

java - ifPresent Stream 的 Else 方法

java - 以编程方式添加 AnnotationSessionFactoryBean

java - 更新到 Android Studio Chipmunk 后单元测试未运行

java - Mockito - 创建一个模拟为 Spring Bean

java - 门户 Controller 的 setContentType 失败

java - Eclipselink:从 JOIN 查询创建对象