我当前团队中最有经验的开发人员根据我们应该遵循的最佳实践制定了一些硬性规则。其中包括“你永远不会模拟域对象”。我问他为什么我们不能,但他从来没有时间给我一个正确的答案。现在他离开了一个星期,我对这条规则的不信任达到了顶峰,这就是我的情况。
我的域对象有一个带有多个参数的Update
方法,其中一个是计算器的接口(interface)。然后它会更新一些字段,运行计算器并将其结果分配给其他一些字段。
Update
方法本身的正确单元测试相当长。
现在我有一段代码可以做一些事情,然后在这样的域对象上调用 Update
。
我通常会模拟对象,并检查是否使用正确的参数调用了 Update
方法。但是现在,我必须通过检查它的字段并模拟计算器来测试它是否被正确调用,然后就像我在单元测试 Update
方法本身时所做的那样。而且我必须在所有调用 Update
方法的地方都这样做。
当 Update
方法稍微改变一下,每一个测试突然崩溃并需要重构时,这将是多么有趣......我觉得这个规则就像搬起石头砸自己的脚......
所以我需要知道,为什么你从不模拟域对象?
最佳答案
You never ever mock domain object
这与其说是最佳实践,不如说是一种启发式方法。我可以想象它在某些项目中是有意义的。
这种启发式方法有助于进行更好的测试。好的测试易于编写、易于阅读,一旦出现问题,它们就会崩溃。如果你模拟你的域模型,你可能还必须模拟它的行为。如果你的模型中有一些复杂的行为,模拟它会很耗时。测试也将更加脆弱(在预测域模型输出时可能会发生错误)。
另一种选择是进行社交单元测试。这意味着要测试的单元将不是孤立的单个类,而是一个类及其一些依赖项。换句话说,您只需在测试中使用域模型的具体对象。
I would normally mock the objects, and just check the Update method is being called with the proper arguments. But now, I have to test it's being properly called, by checking its fields and mocking the calculator then same way I did when unit testing the Update method itself.
检查更新方法是否被调用并不一定意味着测试成功。这可能不是您想检查您的服务是否正常工作的内容。如果您通过了模型的具体类(包括计算器),您将不必进行任何无用的检查或重复其他测试中已完成的操作。
此解决方案与单独测试类的区别之一是,当您的域模型中存在错误时,许多其他测试将失败。但我认为这完全没问题,因为无论如何都必须修复它。
关于unit-testing - 不要模拟域对象规则?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53371495/