测试模拟方法是否被调用的重点是什么?

Kar*_*ran 7 unit-testing mocking

好的,这可能是一个危险的问题.我已经做了一段时间的单元测试,但由于某种原因,我今天早上醒来,我问自己这个问题.

假设我有一个UserFactory接口,它有CreateUser方法.

在某些时候我需要创建一个用户权利?所以我创建了一个测试,检查是否在适当的位置为UserFactory调用了CreateUser.

现在,单元测试非常适合实际代码 - 这很好.但也许有点太多了?同样,打破测试的唯一方法是不调用CreateUser.我们没有检查它的实现等,但只是检查接口已被调用.但无论谁删除该调用,都会有一个失败的测试,并最终从步骤中删除验证语句以验证CreateUser是否被调用.

我已经看到这种情况一次又一次地发生.

有人可以把光带回给我并解释为什么验证模拟对象的方法被调用是有益的吗?我可以看出为什么设置它们可能有用,比如CreateUser应该为后面的部分代码返回一个虚拟用户,但是在我们简单的地方并且只验证它们是否被调用是得到我的部分.

谢谢!

Aug*_*sto 2

验证模拟对象通常是一种必要的罪恶,正如您所提到的,单元测试有时确实与被测类紧密耦合。

我不知道如何回答你的问题,但我会尽力。

以这段代码为例,其中 userRepository 是一个依赖项(这个例子不太好)。

public void doSomething(User user) {
    if( user.isValid() ) {
        userRepository.save(user)
    } else {
        user.invalidate();
    }
}
Run Code Online (Sandbox Code Playgroud)

测试这一点的一种方法是插入连接到数据库的真实存储库,并验证用户是否已保留。但由于我正在进行单元测试,因此我的测试中不能有外部依赖项。

现在,您还有哪些其他选项来验证用户有效的场景?由于 userRepository.save() 返回 void,因此验证副作用的唯一方法是验证是否调用了模拟。如果我不验证模拟,那么单元测试就不会很好,因为我可以删除保存对象的行,并且测试仍然会通过。

对于一些返回值的模拟,情况并非如此,然后在方法中使用该值。这通常意味着如果模拟返回 null,那么应用程序将抛出 NullPointerException(在 java 的情况下)。