sql - 用具有嵌入式SQL的旧Delphi代码执行TDD的好方法是什么

标签 sql delphi testing tdd bdd

我必须使用一些指向数据库的遗留Delphi代码,并使其支持具有完全不同的架构的新的,更好的数据库。更新的数据库具有相同的数据。它具有存储过程和嵌入式SQL的组合。

有没有一种好的测试驱动开发技术,可以确保我不会破坏任何东西?这段代码几乎没有单元测试,我需要对很多硬编码的SQL进行更改。

仅在每次更改后运行听起来容易出错且耗时。我喜欢做TDD或BDD的想法,只是不确定如何去做。

最佳答案

您想参加单元测试是件好事,但我想提醒您,不要过分狂热。

在遗留代码中添加单元测试是一项艰巨的任务,仅添加测试用例而停止其他工作几乎总是不可行的。此外,除非您已经拥有TDD经验,否则学习曲线本身可能会成为克服困难的障碍。

但是,如果您坚持不懈,并且一次迈出第一步,最终您的努力就会得到回报。

您可能会遇到的问题:


传统的应用程序通常很难与测试用例“重新适应”。这是因为在编写代码时并未考虑到可测试性。

许多例程做太多事情,因此测试必须考虑大量的副作用。
代码不是正确的独立代码,因此为测试设置前提条件是很多工作。
通常,缺少测试/检查行为的入口点,因为生产代码不需要它们。因此没有放在第一位。
代码通常依赖于某个地方的全局状态。直接或通过Singleton's。这种全局状态(无论位于何处)会对您的测试用例造成严重破坏。

从本质上讲,数据库的单元测试比其他类型的单元测试更加困难。原因是测试用例不喜欢全局状态-数据库实际上是全局状态的大型容器。问题以多种方式表现出来:

如果您使用IDENTITY列,Auto Inc或任何形式的数字生成器:这些将导致每次测试运行之间存在特定的差异,或者您需要一种在测试之间重置这些数字的方法。
数据库很慢。一旦建立了大量的测试用例,在每次更改之间运行所有测试将是不切实际的。 (我的一个Db测试套件要花近10分钟才能运行。)
如果您的数据库生成日期/时间值,这些值也会使测试复杂化。特别是如果数据库在其他计算机上运行。
由于数据库有两个方面,因此数据库测试变得很复杂:其架构和数据。因此,如果您要测试新的/更改的存储过程(架构的一部分),则需要对数据以及架构的其他方面(例如表/视图)进行适当的更改。

即使没有上述额外的麻烦,您也必须解决“正常问题”。

全球国家常常在一些尴尬的地方出乎意料地出现。考虑Now()返回TDateTime。它使用全局状态:当前日期时间。如果您的系统中有基于时间/日期的规则,则这些规则可能会返回不同的结果,具体取决于运行测试的时间。除非找到有效的方法来应对这一挑战,否则您将有许多“不稳定”的测试用例。
编写测试用例是与大多数开发人员习惯上截然不同的编程范例。打破旧习惯可能非常困难。测试用例代码的样式几乎是声明性的:鉴于此,当我这样做时,我希望这种情况已经发生。测试用例必须简单明了,明确要达到的目的。
学习曲线可能很棘手。最初,如果您不熟悉测试用例,您可能会花费3倍的时间来编写代码。即使最终会有所改善(甚至可能达到比进行非结构化和偶然性测试的速度都要快的程度),但周围的其他人仍可能会感到沮丧。 (如果是你的老板,那太酷了。)



希望我没有灰心,我确实有一些实用建议:

俗话说:“咬不下,嚼不烂。”
准备好开始缓慢。目前,以您熟悉的方式进行大部分工作。但是,每天强迫自己编写1或2个测试用例。当您感到更舒适时,可以增加此数字。

尝试坚持“久经考验的原则”
TDD的工作流程是:首先编写测试,并确保测试失败。我知道很难坚持这个习惯,但是该原则具有非常重要的目的。这是对您的测试用例可以证明其错误/缺失功能的确认。我经常看到测试用例代码在生产变更发生或不发生的情况下会通过-使测试有些无用。

对于数据库测试,您需要建立一个适合您的框架。
首先,您需要一种将数据库设置为“基本状态”的机制。您可以通过所有测试通过的测试-无论执行什么顺序或执行多少次。通常,这将涉及测试之间的某种复位(但需要非常快)。其次,您需要一种简单的方法来将数据库的架构更新为生产代码所期望的形式。

最初,您只想测试新功能或错误修复。
避免测试所有内容的诱惑。随着时间的流逝,您的测试用例覆盖率将会增加。一旦建立了框架和模式,您可能就有机会开始添加测试以增加覆盖范围。

重构现有代码。
当您熟悉测试时,您将了解使测试变得更加困难的编码习惯。您可能会在遗留代码中发现许多此类问题。这样的代码将无法进行测试。您可能需要重构代码,然后才能进行测试。显然,这不是理想的选择,因为您宁愿拥有始终通过的测试来证明您的更改没有破坏任何内容。一本关于重构的好书将为您提供一些可以使用的技术,这些技术可以在不更改代码行为的情况下更改代码的结构。

测试现有代码。
为现有例程编写测试时,请查看代码并确定可能影响不同行为的每个输入。例如。当存在if语句时,将导致条件评估为True,而其他则为False。至少,您需要对每个排列进行测试。

关于sql - 用具有嵌入式SQL的旧Delphi代码执行TDD的好方法是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18636503/

相关文章:

MySQL - 哈希分区不起作用

php - 循环到每条记录并计算mysql

delphi - 透明背景TStringGrid

r - 如何在 R 中使用 testthat 处理 "example files"?

sql - 来自嵌套 JSON 数组的 MarkLogic TDE XPath 值

php - 如何在 JOIN 子句中使用 SELECT 语句?

delphi - DFM 文件中属性的顺序重要吗?

Delphi:WebBrowser 的 OnDownloadComplete 一次发生多次

java - 在构建 spring boot 应用程序时排除一些测试类

r - 在 RUnit 或 testthat 中自动生成测试用例