Moh*_*gar 3 java unit-testing mockito
我正在努力知道如何决定应该模拟与我的测试对象交互的哪些对象。
class MyClass {
private Customer customer;
private Invoice invoice;
private PrintService ps;
private DBAccessService da;
private EmailService em;
..........
}
Run Code Online (Sandbox Code Playgroud)
我可以看到最后 3 个将被嘲笑,因为它们处理一些外部系统。客户和发票怎么样?如果没有,为什么?
“我应该模拟与我的测试对象交互的所有对象吗?”这个问题的一般答案 是一个响亮的“不”:这不是你应该内化或遵循的规则。模拟是多种类型的测试替身之一,您必须判断在哪里使用模拟,在哪里使用其他假货或测试替身,以及在哪里使用真正的合作者。我确实同意您的决定,即最后三个字段(服务)可能值得嘲笑,如果由我决定,我会为前两个字段(客户和发票)使用真实对象。
在这里,我将遵循一条准则,不要模拟数据对象,这是根据一些观察得出的:
数据对象通常具有极高的状态性,而模拟框架往往无法很好地存根状态。Mockito 并没有真正的“getX无限期地返回 15,直到您调用setX(20),然后getX返回 20”的良好语法。因此,正确地存根通常很困难。
对于只是字段/获取器/设置器的数据对象,通过从实际实现中读取可变状态来验证这一点并没有多大价值。谁关心是否getY被调用,只要读取了对象中的值即可?setY只要正确的值最终出现在对象中,谁会关心被调用了多少次呢?因此,验证通常是不必要的。
数据对象通常是在使用它们的对象之前编写的,因此通常已经存在一个可用的实现。
数据对象通常具有确定性行为,很少有外部交互,因此在提高测试稳定性或减少测试不稳定方面通常收效甚微。
正如biziclop在问题评论中提到的那样,
永远记住自动化测试的目的是什么:以尽可能小的努力在尽可能短的时间内发现错误。或者扭转局面:建立对代码正确性的信心。
从这个意义上说,模拟数据对象对测试的可读性和正确性造成很高的成本,并且也不太可能提供有关测试正确性或稳定性的好处。我会避免它。