【问题标题】:Why is this Mockito.mock object being called instead of being mocked?为什么这个 Mockito.mock 对象被调用而不是被模拟?
【发布时间】:2019-05-01 21:51:59
【问题描述】:

我正在对我的类进行单元测试并遇到了这种情况:我使用 Mockito 模拟一个对象并在该对象上调用一个方法。当我这样做时,我希望真正的方法不会被调用,并且程序流程会继续。正在发生的事情是调用了真正的方法并且我得到了 NullPointerException,因为如果我使用此参数调用该方法会发生这种情况。

Mockito.mock 不应该阻止这种行为吗?

Mockito documentation 表示 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, ...).this answer 确认了我对 In a mock all methods are stubbed and return "smart return types". This means that calling any method on a mocked class will do nothing unless you specify behaviour. 的预期行为

代码:

public class BrokenTest {
    @Test
    public void shouldPassBecauseItIsMocked() throws IOException {
        Object anyObject = Mockito.mock(Object.class);
        ObjectOutputStream objectOutputStream = Mockito.mock(ObjectOutputStream.class);
        objectOutputStream.writeObject(anyObject);
    }
}

我希望这个测试能够通过,但我得到了 NullPointerException:

java.lang.NullPointerException
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1108)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
    at packageName.BrokenTest.shouldPassBecauseItIsMocked(BrokenTest.java:14)
    ...

BrokenTest.java:14 实际上是objectOutputStream.writeObject(anyObject); 行)

P.S.:我并不是真的想测试ObjectOutputStream,而是我的一类使用ObjectOutputStream.writeObject(Object object)。当我做myObjectWithMockedObjectOutputStream.methodThatCallsWriteObject()时,问题真的出现了

【问题讨论】:

  • writeObject 是最终的。 Mockito(直到最近的版本,如果你专门配置它)不能模拟最终方法。
  • 您实际上是在模拟 Object.class 还是其他特定类型?另外,您知道您使用的是哪个版本的 Mockito/JUnit?
  • @JBNizet 我想就是这样。将在这里检查和评论。当我执行类似的操作时,它通常会显示警告,例如 Mockito.mock(String.class) 但可能是因为我使用的是旧版本的 Mockito (1.10.19)。
  • @JJBrown 是的,实际上是在模拟 Object.class。并使用 1.10.19(这可能是一个问题,正如我对 JB Nizet 的评论......)
  • 是的,@JBNizet 是解决方案。如果你想写一个答案,我会接受。

标签: java unit-testing mocking mockito


【解决方案1】:

Mockito 不会改变语言的工作方式。这些方法按照它们在代码中出现的顺序被调用。 这意味着对于像这样的模拟方法:

when(mockObject.getSomething()).thenReturn(SOMETHING_ELSE);

首先在模拟对象上调用getSomething(),然后mockito 的基础结构替换返回值,然后将控制权交给您的被测代码。

这意味着如果getSomething() 调用模拟对象的某些依赖项,则后者不会被初始化并导致 NPE。

解决此问题的方法是使用另一种配置模拟的形式:

doReturn(SOMETHING_ELSE).when(mockObject ) .getSomething();

请不要将when 的右大括号从方法后面移到. 之前。

这允许 Mokito 拦截完整的方法调用,从而不会抛出 NPE。

【讨论】:

    【解决方案2】:

    JBNizet 正确回答了 cmets 的问题。

    writeObject 是最终的。 Mockito(直到最近的版本,如果你专门配置它)不能模拟最终方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-12-18
      • 1970-01-01
      • 2015-11-15
      • 2014-12-02
      • 2021-07-21
      • 1970-01-01
      • 1970-01-01
      • 2011-06-05
      相关资源
      最近更新 更多