单元测试返回复杂数据集的类

时间:2010-10-19 07:56:27

标签: delphi unit-testing refactoring legacy-code

经过数月的挫折和在先前开发人员的巫毒娃娃中插入针头的时间之后,我决定尝试重构遗留代码更好。

我已订购Micheal Feather's book,我已进入Fowler's refactoring,我使用DUnit制作了一些示例项目。

所以即使我不掌握这个主题,我觉得是时候采取行动并将一些想法付诸实践。

我工作的代码几乎100%都有业务逻辑被困在UI中,而且所有都是过程式编程(除了少数例外)。该应用程序以快速和快速开始肮脏的,并继续这样。

现在为我的所有应用程序编写测试都是毫无意义的任务,但我想尝试对需要重构的东西进行单元测试。

一个大的“TForm业务逻辑类”的复杂任务之一是读取DB数据,进行一些计算并填充调度程序组件。我想删除读取数据库数据和计算部分,并将此任务分配给新类。当然这是一种改进当前设计的方法,它不是从头开始的最佳方式,但我想这样做是因为这个新类返回的数据在其他方面也很有用,例如现在我已被要求发送调度数据的电子邮件通知。

因此,为了避免大规模的复制和粘贴操作,我需要新的类。

现在,调度程序是从庞大的数据集(大小和字段数量)中填充的,可能第一个重构步骤可能是从新类中获取数据集。但是在将来我最好使用一个新类(比如TSchedulerData或其他一些不太受调度程序限制的名称)来管理数据,而不是将数据集作为结果,我可以拥有一个TSchedulerData对象。

由于重构是在小步骤发生的,并且需要进行更好的重构测试,所以我对如何继续进行了一些混淆。

我不清楚以下几点:

1)如何测试复杂的数据集?我应该运行工作应用程序,将一个结果集保存到xml,并在我使用包含该xml数据的TClientDataSet的地方编写测试吗?

2)我需要多少关心TSchedulerData?我的意思是我不是100%肯定我会使用TSchedulerData,可能我会坚持使用数据集,无论如何考虑创建将在2周内丢弃的复杂测试对DUnitNewbee没有吸引力。无论如何,这可能是它的工作原理。我无法想象没有测试我会遇到的错误数量。

最后说明:我知道有人认为从头开始重写是一个更好的选择,但这不是一个选择。 “该应用程序非常庞大,今天已售出,今天需要新功能才能停止运营”。这就是我被告知的,无论如何,重构可以挽救我的生命并延长应用程序的使用寿命。

2 个答案:

答案 0 :(得分:2)

我会说在专注的婴儿步骤中接近它。

步骤1:应始终围绕您的入侵区域进行一些测试TForm - 回归测试又称安全网。在您的情况下,感知应用程序正在做什么。从我读到的,它似乎是一个数据转换器。因此,花时间了解所有(或最重要的,如果一切都不可行)输入数据和相应的输出计划的组合。把它们写成测试。确保所有测试都通过。

步骤2:现在尝试重构。所有这些都是在回归网的安全下将代码块移动到内聚类中。

测试复杂数据集 - 测试文件转储应该是最后的选择。但在这种情况下,它似乎是一个简单的选择入门。也许您以后可以使用自己的Equals()实现将其作为第一类域对象TSchedule。 推迟设计决策/更改,直到您的修改区域周围有一个可靠的回归测试套件。

答案 1 :(得分:2)

您最终的目标是将UI,数据存储和业务逻辑分离到不同的层中。

使用自动测试框架测试UI非常困难。您最终希望尽可能多地将业务逻辑与UI分开。这可以使用各种模型/视图/ *模式之一来完成。我更喜欢MVP被动视图,它试图使UI只不过是一个界面。如果您正在使用数据集MVP监督控制器可能更适合。

数据存储需要有自己的测试套件,但这些测试与单元测试不同(尽管您可以使用相同的单元测试框架),但通常较少。你可以侥幸成功,因为大部分繁重的工作都是由第三方数据组件和dbms(在你的情况下为T * Dataset)完成的。这些是集成测试。基本上确保您的代码与供应商的代码一致。如果您在DB中定义了任何存储过程,也需要。它们比单元测试慢得多,并且不需要经常运行。

业务逻辑是您最想测试的。每个计算,循环或分支应至少有一个测试(更多是更好的)。在遗留代码中,此逻辑通常直接触及UI和db,并在单个函数中执行多项操作。这里提取方法是你的朋友。提取方法的好地方是:

for I:=0 to List.Count - 1 do
begin
  //HERE
end;

if /*HERE if its a complex condition*/ then
begin
  //HERE
end
else
begin
  //HERE
end

Answer := Var1 / Var2 + Var1 * Var3; //HERE

当您遇到其中一个提取点时

  1. 确定您希望新方法的方法签名是什么样的:方法名称,参数,返回值。
  2. 编写一个调用它的测试并检查预期结果。
  3. 提取方法。
  4. 如果一切顺利,您将获得一个新提取的方法,至少有一个通过单元测试。

    Delphi内置的提取方法并没有为您提供任何调整签名的方法,所以如果这是您自己的选项,您必须在提取后进行修复。您还需要公开新方法,以便测试可以访问它。有些人不愿公开私人公用事业方法,但在这个早期阶段你别无选择。一旦你取得了足够的进展,你就会开始看到你提取的一些实用方法属于他们自己的类(在这种情况下,他们必须公开),而其他方法可以被私有/保护并间接测试通过测试依赖于它们的方法。

    随着您的测试套件的增长,您需要在每次更改后运行它们,以确保您的最新更改不会破坏其他地方。

    此主题太大,无法完全覆盖答案。当这本书到来时,你会发现绝大多数问题都已被涵盖。

相关问题