欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

大话重构连载12:你不能没有保险索

程序员文章站 2022-05-05 13:31:31
...
通过前面的描述你已经对重构中“小步快跑”的开发模式有了一个清楚的认识。学会和习惯小步快跑的开发模式,对于重构工作极其重要,因为它让这种大范围、大幅度修改代码的重构工作变得不再像以往那样让人胆战心惊。究其原因,虽然从结果上是在大范围、大幅度调整,但每一步却是小范围、小福度调整,并且能保证每一步都是正确的。

然而,这里有一个非常重要的假设条件,那就是“保证每一步都是正确的”,这是怎么保证的呢?就这个问题,我们需要展开来认真讨论讨论。

毫无疑问,系统重构就其结果来看,是在对软件系统进行大范围、大幅度的改动,而这种改动过去我们是无法想象的,因为它实在是改动太大了,一不小心就会产生一个毁灭性的结果。这就是许多人不敢轻易尝试系统重构的重要原因。

是的,这就是真相,如果你不能正确地验证每一步系统重构是否正确,或者你的验证方式存在缺陷,即使小步快跑也不能解决重构带来的风险。所以我们说,系统重构,你不能没有保险索。这个保险索就是每次重构后正确的测试方法。

什么是程序代码正确的测试方法,其在不同的场景中标准是不一样的。但与其它测试不同,系统重构在测试代码正确性方面却有自己独特的方法。系统重构,从自身的定义上就把其代码正确性的验证方式描述得十分明白,那就是“不改变软件外部行为”。

“不改变软件外部行为”,我们可以从多个层面上看待这个问题。首先从功能层面上看,重构前系统提供给用户什么样的功能,重构后也应当提供同样的功能。说得更加具体一些,重构前,用户从界面上输入什么内容,发出什么请求,得到什么结果,那么重构后用户应当得到同样的结果。这种结果可能体现在前端界面所展现的结果中,也可能体现在此处操作后存入数据库的数据中,即重构前后系统存入数据库的数据也应当是一致的。存入数据库的数据同样是测试中系统输出的一种。

从功能层面再往下钻就到了代码层面。打开我们的软件系统,有各个层次、各项接口和各种函数。我们进行系统重构往往是在某个层次、某项接口或某个函数上进行的重构。比如,我们对某项接口进行重构,那么我们可能会修改这个接口的实现类、方法函数、底层调用类,但不论怎么修改,这个接口必须保持不变。也就是说,我们代码层面的重构,“不改变软件外部行为”是针对的这个接口。你可以重构接口内部,但必须保证接口外部是不变的。

所以,系统重构的测试可以从两个层面来进行:系统测试与单元测试。系统测试往往是一种手工测试,当然也可以使用QTP等工具进行一些简单的录制。重构前我们首先通过需求文档确认系统现有功能,根据现有功能设计测试用例。然后进入系统,确保每个测试通过,并录制成QTP脚本。这样,我们对重构的准备工作就完成了。在整个测试过程中,我们每完成一次重构就去手工执行这些测试,或者执行QTP脚本,保证每个测试通过。如果测试不通过,则要么寻找问题原因并解决,要么就恢复到上次测试的版本,此次重构宣布失败。

反复地手工进行同样的测试是一件比较烦人的事,因此你可以有两个选择:录制QTP脚本,以及在接口层面建立自动化测试程序。这里所说的自动化测试程序是指那些基于JUnit编写的自动化测试程序,它实际上是在代码层面进行的单元测试。建立自动化测试的关键在于我们在哪个层面建立测试。代码有许多层次,有函数级别、有类级别、有接口或抽象类级别,从系统分层结构来说有底层、DAO层、BUS层、Web层。每次重构都是站在某个层次进行重构,因此自动化测试代码也应当在这个层次上写。比如最初的重构是在函数层次上进行的,就应当对函数写测试代码;后来在对象层次上进行重构,就对对象写测试代码;再到接口层次……

与手工测试一样,在系统重构前,我们首先保证原有代码自动化测试通过。然后执行重构,保证每次重构都能够测试通过,如此往复。但重构中的自动化测试有一个问题就是,测试接口不太稳定。起初是在函数级别进行的重构,我们写了针对函数的测试代码。但随着重构的深入,我们开始在对象层面进行重构了,我们可能要调整原有的函数。这时将意味着原有的针对函数编写的测试代码将失效而必须要遗弃,这不得不说是一种浪费。因此我给大家的建议是,不要过早编写自动化测试代码,它不一定能节省我们的时间,甚至可能花费更多。最初的重构可以采用手工测试或QTP测试的方式进行。

大话重构连载首页:http://fangang.iteye.com/blog/2081995
特别说明:希望网友们在转载本文时,应当注明作者或出处,以示对作者的尊重,谢谢!