我必须使用一些指向数据库的遗留 Delphi 代码,并使其支持具有完全不同模式的新的、更好的数据库。更新后的数据库具有相同的数据。它结合了存储过程和嵌入式 SQL。
有没有一种好的测试驱动开发技术可以帮助确保我不会破坏任何东西?这段代码几乎没有单元测试,我需要对很多硬编码的 SQL 进行更改。
在每次更改后运行听起来容易出错且耗时。我喜欢做 TDD 或 BDD 的想法,只是不知道该怎么做。
你想进入单元测试是件好事,但我想提醒你不要过度热心地接受它。
将单元测试添加到遗留代码是一项重大任务,而仅仅为了添加测试用例而停止其他工作几乎总是完全不可行的。此外,除非您已经有 TDD 方面的经验,否则学习曲线本身可能会成为一个难以克服的障碍。
但是,如果你坚持不懈,一步一步地做事,你的努力最终会得到回报。
您可能会遇到的问题:
Now()
哪个返回 TDateTime。它使用全局状态:当前日期时间。如果您的系统中有基于时间/日期的规则,则这些规则可能会根据您的测试运行时间返回不同的结果。除非您找到应对这一挑战的有效方法,否则您将拥有许多“不稳定”的测试用例。俗话说“嚼不烂”。
准备慢慢开始。暂时,以你熟悉的方式继续你的大部分工作。但是强迫自己每天写一两个测试用例。随着您变得更加舒适,您可以增加这个数字。
Try 坚持“久经考验的原则”
TDD 的工作流程是:首先编写测试并确保测试失败。我知道很难坚持这个习惯,但这个原则有一个非常重要的目的。这是您的测试用例证明错误/缺失功能的确认级别。我经常看到测试用例代码在有/没有生产更改的情况下都会通过 - 使测试有些无用。
对于您的数据库测试,您需要建立一个适合您的框架。
首先,您需要一种使数据库进入“基本状态”的机制。您的所有测试都应该能够通过的一种——无论它们运行什么顺序或多少次。通常这将涉及测试之间的某种重置(但它需要非常快)。其次,您需要一种简单的方法来将数据库的模式更新为生产代码所期望的。
最初,您只想测试新功能或错误修复。
避免测试一切的诱惑。随着时间的推移,您的测试用例覆盖率将会增加。一旦你的框架和模式建立起来,你就有机会开始添加测试来增加覆盖率。
重构现有代码。
随着您对测试的熟悉,您将了解使测试变得更加困难的编码习惯。您可能会在遗留代码中发现许多此类问题。这样的代码将无法按原样进行测试。你可能需要在测试之前重构你的代码。显然这并不理想,因为您宁愿让测试始终通过以证明您的更改没有破坏任何东西。一本关于重构的好书会给你一些你可以使用的技术,这些技术将改变你的代码结构而不改变它的行为。
测试现有代码。
在为现有例程编写测试时,请查看代码并确定可能影响不同行为的每个输入。例如,当有if语句时,某些情况会导致条件评估为 True,而其他情况则为 False。至少,您需要对每个排列进行测试。
在您的位置,我将使用DUnit创建一个单元测试项目。对于每个实体,我会编写运行新旧句子的测试方法,然后编写方法来比较结果。
我会编写一个名为 TTestCase 的类,比如说TMyTestCase,并向其中添加一些辅助方法,然后将我的新测试类创建为TMyTestCase的子类。
祖先类的想法是提供通用功能,使编写测试(例如比较方法)更容易,以提高生产力和舒适度。
您可以开始构建数据库模拟器。连接它而不是旧的,看看它需要做什么。虽然工作量很大