反对testbackdoor模式的争论

时间:2013-11-12 11:06:34

标签: unit-testing tdd integration-testing

我将在公司内部进行一次关于测试的简短讲座。你能不能给我一些很好的例子,为什么所谓的测试门模式被认为是魔鬼? 我确信这是一种反模式,但我也想向同事们指出这一点。

我觉得testbackdoor会引起头痛,但是我无法真实地描述为什么会这样。

2 个答案:

答案 0 :(得分:0)

Back Door Manipulation在您的测试和SUT使用的夹具之间创建耦合,这意味着如果夹具的实现发生变化,那么您可能还需要更新测试。但是,当您重构SUT时,测试应该允许您确认重构没有改变SUT的行为。如果重构以一种需要您更改测试的方式更改了夹具,则无法执行此操作。

例如,假设您正在测试一个在私有字段中维护状态的类,并且您使用后门操作来修改这些字段以进行设置并检查字段的值以进行验证。然后重构该类(例如)以删除字段中的一些冗余并在字段中使用更合适的类型。您的测试现已中断,您无法确保类的行为未发生变化。您可以更改测试以使用新字段,但是您如何确定测试仍在测试相同的行为并且您没有在SUT和测试中引入错误?

答案 1 :(得分:0)

当在单元测试中使用时,后门操作模式启用并鼓励继续依赖外部依赖。它可以违反依赖性倒置原则。这允许危险的做法,例如全局变量。它将您的测试和开发工作与外部数据库结合起来。

什么是单元测试?

单元测试是测试代码的一个单元的测试,而不是系统的功能。它通过一种方法测试一条路径。它不应该尝试测试数据库。它不应该尝试测试代码的其他功能。它应该只测试你在屏幕上看到的少量代码。

Globals很糟糕。

考虑全局变量是什么,以及它们为什么会出现这样的问题。他们隐藏着你依赖的其他人可以改变的状态。如果有人在程序中的任何其他位置更改了该值,则代码的行为会有所不同。因为在您的界面上看不到全局,所以想要重用您的代码的人不会知道全局的重要性。 Globals违反封装,因此您的代码是非模块化的。 Globals使代码难以理解,难以重用,难以测试并导致错误。

使用后门操作,您仍然可以编写设置全局的单元测试,运行测试,然后检查全局。该测试使全球能够继续存在。但是测试并没有真正证明你的代码,因为任何其他代码都可以随时改变全局。相反,应该重构代码以使接口在依赖注入模式之后传入变量。这样,无论谁试图重用您的代码,都会知道他们必须提供这段数据。尝试重用代码的人没有任何隐藏的内容。

数据库大于单位。

考虑为什么依赖数据库对单元测试不利。测试系统需要具有可用的数据库才能运行测试。开发人员需要拥有可用的数据库才能运行测试和开发。必须启动数据库的网络。数据库服务器必须具有正确的数据库,正确的模式,正确的用户,正确的存储过程,正确的表,正确的行和正确的值。用户和测试服务器必须具有有效的凭据和密码才能访问网络,服务器和数据库。开发人员的数据库和测试数据库都必须使用相同的SQL方言。即使应用程序的访问需要是只读的,测试也需要写访问才能设置测试。共享数据库的测试可能会受到使用数据库和修改内容的其他人的干扰。开发人员的工作站和测试服务器必须安装正确的数据访问对象。如果其中任何一个是问题,测试停止并且测试驱动的开发停止。

这些依赖关系都没有证明代码或生产环境的工作。因此,它们的设置和维护成本很高,它们没有对实际代码进行测试的证据添加任何内容,它们可以使编码停止,并且所有测试和开发始终都需要可用性。

相反,代码应该使用依赖注入来传递数据库连接(或所需的数据,或其他)。单元测试工具可以注入伪造或模拟数据库连接,该连接将准确返回建立测试条件所需的数据。正确编写后,自动化单元测试系统将完美运行,无法访问数据库。作为奖励,在没有等待数据库访问的情况下,从模拟对象获取数据时,测试将以更快的速度运行。当你有50,000次单元测试来运行每个构建时,这很重要。

后门操作何时适当?

后门操作的想法非常适合自动化系统测试和自动化集成测试。他们可以证明用户级功能在存在正确数据的情况下工作。他们可以证明用户级函数适当地操纵数据库中的数据。

后门操作通常是为遗留代码编写单元测试的最有效方法。遗留代码是没有单元测试的代码,对许多现有项目来说都是现实。后门操作可以帮助开发人员编写测试,以确保遗留代码的持续稳定性,即使存在持续的修改。它可能不是保存好的代码,但它仍然需要与代码保持一段时间。

但是在测试驱动开发新代码期间在单元测试中完成时,使用后门操作会鼓励测试大于单元测试。这对自动化单元测试来说是不利的,因为它可以使测试驱动的开发停止。它对代码质量和重用很不利,因为它支持非模块化代码。