我已订购Micheal Feather’s book,我已进入Fowler’s refactoring,我用DUnit制作了一些示例项目.
所以即使我不掌握这个主题,我觉得是时候采取行动并将一些想法付诸实践.
我工作的代码几乎100%都包含在UI中的业务逻辑,而且所有都是过程式编程(除了少数例外).该应用程序以快速和快速开始肮脏的,继续这样.
现在为我的所有应用程序编写测试都是毫无意义的任务,但我想尝试对需要重构的东西进行单元测试.
一个大的“TForm业务逻辑类”的复杂任务之一是读取DB数据,进行一些计算并填充调度程序组件.我想删除读取数据库数据和计算部分,并将此任务分配给新类.当然这是一种改进当前设计的方法,它不是从头开始的最佳方式,但我想这样做是因为这个新类返回的数据在其他方面也很有用,例如现在我已被要求发送调度数据的电子邮件通知.
因此,为了避免大规模的复制和粘贴操作,我需要新的类.
现在,调度程序是从一个巨大的数据集(大小和字段数量)填充的,可能第一个重构步骤可能是从新类中获取数据集.但是在将来我最好使用一个新类(比如TSchedulerData或其他一些不太受调度程序限制的名称)来管理数据,而不是将数据集作为结果我可以拥有一个TSchedulerData对象.
由于重构发生在小步骤并且需要测试以更好地重构我对如何继续进行有点困惑.
我不清楚以下几点:
1)如何测试复杂的数据集?我应该运行工作应用程序,将一个结果集保存到xml,并编写一个测试,我使用包含该xml数据的TClientDataSet吗?
2)我需要多少关心TSchedulerData?我的意思是我不是100%肯定我会使用TSchedulerData,可能我会坚持使用数据集,无论如何想要创建将在2周内丢弃的复杂测试对于DUnitNewbee并不吸引人.无论如何,这可能是它的工作原理.我无法想象没有测试我会遇到的错误数量.
最后说明:我知道有人认为从头开始重写是一个更好的选择,但这不是一个选择. “该应用程序非常庞大,今天已售出,今天需要新功能才能停止运营”.这就是我被告知的,无论如何,重构可以挽救我的生命并延长应用程序的使用寿命.
解决方法
使用自动测试框架测试UI非常困难.您最终希望尽可能多地将业务逻辑与UI分开.这可以使用各种模型/视图/ *模式之一来完成.我更喜欢MVP被动视图,它试图使UI只不过是一个界面.如果您正在使用数据集MVP监督控制器可能更适合.
数据存储需要有自己的测试套件,但这些测试与单元测试不同(尽管您可以使用相同的单元测试框架),但通常较少.你可以侥幸成功,因为大部分繁重的工作都是由第三方数据组件和dbms(在你的情况下为T * Dataset)完成的.这些是集成测试.基本上确保您的代码与供应商的代码一致.如果您在DB中定义了任何存储过程,也需要.它们比单元测试慢得多,并且不需要经常运行.
业务逻辑是您最想测试的.每个计算,循环或分支应至少有一个测试(更多是更好的).在遗留代码中,此逻辑通常直接触及UI和db,并在单个函数中执行多项操作.这里Extract Method是你的朋友.提取方法的好地方是:
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
当您遇到其中一个提取点时
>确定您希望新方法的方法签名是什么样的:方法名称,参数,返回值.
>编写一个调用它的测试并检查预期结果.
>提取方法.
如果一切顺利,您将获得一个新提取的方法,至少有一个通过单元测试.
Delphi内置的Extract Method不会给你任何调整签名的方法,所以如果这是你自己的选择,你必须在提取后做并修复它.您还需要公开新方法,以便测试可以访问它.有些人不愿公开私人公用事业方法,但在这个早期阶段你别无选择.一旦你取得了足够的进展,你就会开始看到你提取的一些实用方法属于他们自己的类(在这种情况下,他们必须公开),而其他方法可以被私有/保护并间接测试通过测试依赖于它们的方法.
随着测试套件的增长,您需要在每次更改后运行它们,以确保您的最新更改不会破坏其他地方.
这个主题太大了,无法完全覆盖答案.你会发现,当这本书到来时,你的绝大多数问题都会被涵盖.