为什么此Mockito.mock对象被调用而不是被模拟?

时间:2019-05-01 21:52:00

标签: java unit-testing mocking mockito

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

Mockito.mock不能阻止此行为吗?

Mockito documentationBy 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()

时,问题确实出现了

2 个答案:

答案 0 :(得分:0)

Mockito不会改变语言的工作方式。方法按照它们在代码中的排列顺序调用。 这意味着在像这样的模拟方法的情况下:

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

首先在模拟对象上调用getSomething(),然后在控制要测试的代码之前,mockito的基础结构替换返回值。

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

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

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

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

这使Mokito可以拦截完整的方法调用,从而不会引发NPE。

答案 1 :(得分:0)

JBNizet正确回答了问题评论。

  

writeObject是最终的。 Mockito(直到最新版本为止,如果您专门配置为这样做)则无法模拟最终方法。