java - 为什么 null Mock 对象不会抛出 NullPointerException?

标签 java unit-testing mockito

我有一段代码,如下所示:

public void someMethod(ObjectA a) {
    ObjectB b = a.getB();
    b.doSomething();
}

我的测试是:

@Test
public void someTest_1() {
    when(mockA.getB()).thenReturn(mockB);
    ...
    mockB = null;

    someMethod(mockA);
}

上面的代码不应该抛出 NPE 吗?

当我将测试更改为:

@Test
public void someTest_2() {
    when(mockA.getB()).thenReturn(null);

    someMethod(mockA);
}

然后我的代码正确地抛出空指针异常。

我的测试的第一个版本和第二个版本有什么区别?

在我的第一个版本中,我告诉mockA 返回mockB。但我也将mockB设置为null,因此当调用b.doSomething()时,我认为该方法应该抛出一个空指针,因为它试图调用null.doSomething()。

我知道我应该使用第二个版本来实现我想要测试的行为,但我不知道为什么第一个版本有不同的行为。

最佳答案

与:

when(mockA.getB()).thenReturn(mockB);
...
mockB = null;

thenReturn设置mock以返回mockB在那一刻(即执行when ... thenReturn的那一刻)所持有的值,无论mockB随后发生什么。

这与字符串的行为方式没有太大不同:

String s1 = "abc";
String s2 = s1;
s1 = "xyz";

这里的结果是 s2 仍然具有值“abc”,因为这是分配时的值,无论 s1 随后发生什么。

编辑:

考虑这个问题的方法是像 mockB 这样的变量, s1s2是“引用”(又名“指针”)变量 - 也就是说,它们的值指向目标对象内存中的地址。

何时 thenReturn(mockB)s2 = s1被执行,它是mockBs1正在传递或复制 - 即目标对象或字符串的地址(不是变量 mockBs1 本身的地址)。这就是变量mockB的值随后发生变化的原因。或s1本身没有任何影响。

when ... then的定位在哪里对对象本身执行的操作没有影响 - 例如:

when(mockB.getName()).thenReturn("fred");

when(mockA.getB()).thenReturn(mockB);

when(mockB.getAge()).thenReturn(23);
...
mockB = null

when(mockA.getB())的定位不影响(并且不受)getName 的设置和getAge模拟对象的地址,因为这些操作不会更改该对象在内存中的地址。

关于java - 为什么 null Mock 对象不会抛出 NullPointerException?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59853559/

相关文章:

java - Android - OpenCV 错误 : Cannot load info library for OpenCV

java - 通过 SMTP 发送邮件时,自签名 java 小程序引发错误 "Permission denied"

unit-testing - 无法在 golang : "unable to open database file [recovered]"-error 中打开 SQLite 数据库

java - 如果单例类本身正在使用 PowerMock 进行测试,如何模拟该类的私有(private)方法?

java - 期望的结果部分错误 : Jmockit/Junit

java - Junit Mockito 没有像预期的那样 mock

java - Spring Framework 中的 Redis 设置

java - 某些处理完成后如何调试-Java

unit-testing - 在 EmberJS 中对组件进行单元测试的正确方法

java - 如何识别软件中的错误而不是测试人员的错误?