我有以下挑战,我还没有找到一个好的答案。我正在使用 Mocking 框架(在本例中为 JMock)来允许将单元测试与数据库代码隔离开来。我正在模拟对涉及数据库逻辑的类的访问,并使用 DBUnit 单独测试数据库类。
我遇到的问题是,我注意到逻辑在概念上在多个地方重复的模式。例如,我需要检测数据库中的某个值不存在,因此在这种情况下我可能会从方法中返回 null。所以我有一个数据库访问类,它进行数据库交互,并适当地返回 null。然后我有一个业务逻辑类,它从模拟中接收 null,然后在值为 null 时进行测试以适当地采取行动。
现在,如果将来该行为需要更改并且返回 null 不再合适,比如说因为状态变得更加复杂,所以我需要返回一个报告该值不存在的对象以及来自的一些附加事实数据库。
现在,如果我将数据库类的行为更改为在这种情况下不再返回 null,那么业务逻辑类似乎仍然可以正常工作,并且该错误只会在 QA 中发现,除非有人记得耦合,或者正确地遵循了方法的用途。
我觉得我错过了一些东西,必须有一种更好的方法来避免这种概念上的重复,或者至少对其进行测试,以便如果它发生变化,那么没有传播变化的事实会使单元测试失败。
有什么建议么?
更新:
让我试着澄清我的问题。我正在考虑代码何时随时间演变,如何确保通过模拟测试的类和模拟所代表的类的实际实现之间的集成不会中断。
例如,我刚刚有一个案例,我有一个最初创建的方法并且不期望 null 值,所以这不是对真实对象的测试。然后,该类的用户(通过模拟测试)得到增强,可以在某些情况下将 null 作为参数传递。在集成中断时,因为未对真实类进行空值测试。现在,在开始构建这些类时,这没什么大不了的,因为您在构建时正在测试两端,但是如果设计需要在两个月后发展,而您往往会忘记细节,那么您将如何测试它们之间的交互这两组对象(通过模拟测试与实际实现测试的对象)?
潜在的问题似乎是重复之一(即违反 DRY 原则),期望确实保留在两个地方,虽然关系是概念上的,但没有实际的重复代码。
[在 Aaron Digulla 对他的回答进行第二次编辑后编辑]:
对,这正是我正在做的事情(除了在通过 DBUnit 测试并在测试期间与数据库交互的类中与 DB 有一些进一步的交互,但这是相同的想法)。所以现在,假设我们需要修改数据库行为以使结果不同。使用模拟的测试将继续通过,除非 1)有人记得或 2)它在集成中中断。所以数据库的存储过程返回值(比如)在模拟的测试数据中本质上是重复的。现在让我困扰的是重复的逻辑是重复的,这是对 DRY 的微妙违反。可能就是这样(毕竟集成测试是有原因的),但我觉得我错过了一些东西。
[编辑开始赏金]
阅读与 Aaron 的互动就可以找到问题的重点,但我真正想要的是一些关于如何避免或管理明显重复的见解,以便真实班级行为的变化将出现在与 mock 交互的单元测试是有问题的。显然这不会自动发生,但可能有一种方法可以正确设计场景。
[关于奖励赏金的编辑]
感谢所有花时间回答问题的人。获胜者教会了我一些关于如何考虑在两层之间传递数据的新知识,并首先得到了答案。