读书笔记--修改代码的艺术

简介:

本书内容关于如何有效处理遗留代码,遗留代码是指没有编写测试的代码。因此,为遗留代码编写测试是改善遗留代码的首要任务。对一个大系统,不可能从头开始编写每一处的单元测试,一般只能从当前需要改动的地方开始,逐步添加单元测试,形成“软件夹钳”,进而修改并改善现有代码。遗留代码修改算法:   

(1) 确定改动点;(前提:理解代码)

(2) 找出测试点;(前提:理清代码间的联系)

(3) 解依赖;(解依赖是为类编写单元测试的前提 

(4) 编写测试; 编写符合代码当前行为的特征测试 )

(5) 修改、重构。 在存在测试覆盖的前提下,修正bug 、改善设计等 )

从上述算法可以看出,前4 条是关于如何编写测试代码的,而解依赖是编写测试的前提,因为本书很大程度可以说成是关于如何解依赖的书籍,书中也用来很大的篇幅来介绍解依赖技术。当然,解依赖除了处理遗留代码,还可用于指导编写易测试的代码。


测试代码的命名约定:(测试类:DBEngine )

单元测试类:一个类至少要编写一个相应的单元测试类,故单元测试类常常在目标类名上加 “Test”前缀或后缀。为便于浏览,加后缀方便些。DBEngineTest

伪类(伪对象或仿对象):伪类是指用于测试的伪造类。 伪类常用”Fake” 作为前缀,使得所有的伪类都在一起,便于区别。FakeDBEngine

测试子类(testing subclass ): 测试子类是指利用继承将不关心的行为架空使只访问测试所关心的行为的派生子类。 测试子类常由子类化并重写方法技术生产。测试子类本质就是为测试类接触不必要的测试依赖。测试子类常使用“Testing ”前缀。TestingDBEngine

 

遗留代码工作的三个关键概念:感知、分离和接缝 。

感知和分析和解依赖直接相关,解依赖是将类放入测试用具的重要手段( 有时是唯一手段) ,因为类之间往往是相互依赖,相互影响的,为了能单独测试某类,我们需要接触类之间的依赖关系,尤其是测试类所依赖的类。很多时候解依赖唯一的办法就是通过伪装成被影响的类来直接感知所受到的影响。感知和分离式解依赖的两个目的:1) 感知;当无法感知代码的状态 ( 测试) 时,通过解依赖来感知“状态”;2) 分离:当无法将代码放入测试用具时,通过解依赖来分离测试代码。

类难于测试的根本原因在于:类很少是单独存在的,往往是相互依赖。所要测试的类往往存在如下依赖关系:1) 实例对象(成员变量); 2) 委托对象(接口参数); 3) 临时对象(所创建或实例化的任何对象); 4) 全局对象(单体,系统或库API )。

注:上述对象不包括基本类型和基本对象(如STL 等标准库)。

所有的对象都存在自己的逻辑,从而如果想要编写单独的类测试用例就应该接触对这些对象的依赖。下面一一给出解决方案。

1) 实例对象(成员变量):使用伪对象

2) 委托对象(接口参数):使用伪对象

3) 临时对象(所创建或实例化的任何对象):使用伪对象

4) 全局对象(单体,系统或库API ) :以获取方法替换全局引用;封装API ,形成内部调用接口,通过子类化并重写方法,屏蔽不必要的系统API 调用。

 

使用伪对象的解依赖技术:

参数化构造函数:直接传入伪对象。

参数化方法:避免临时对象的硬编码,直接传入伪对象

引入实例委托:避免全局对象的硬编码,直接传入伪对象

替换实例变量:增加实例变量设置接口,不推荐。

引入静态设置方法:用于替换静态对象, 如单体实例。

参数适配:将依赖的参数类型替换成可伪装的自定义类型。

实现提取:用于提取抽象基类或接口 ,进而定义伪对象Fake

接口提取:用于提取抽象基类或接口,进而定义伪对象

 

接触类内部依赖的解依赖技术:

子类化并重写方法 :将少数无须测试的内部接口重写,通过实例化重写的派生类来测试原有类的接口。这里的重写是指虚函数的重实现,而非覆盖。

提取并重写调用:封装API ,并重写该接口

提取并重写工厂方法:用于实例化伪对象,避免更改接口,本质就是替换实例变量。

提取并重写获取方法:延迟获取实例变量,用于C++ 。因为C++ 在构造函数中虚函数机制被禁止,故无法再构造函数中调用子类重写的工厂方法。

 

特定情况下的解依赖技术:

分解出方法对象:重构巨型方法

朴素化参数:避免参数依赖

封装全局引用:

以获取方法替换全局引用:利于重写获取方法。

定义补全:C/C++ 的定义和实现是分开的,通过重写实现替换原有行为。

连接替换:利用链接期接缝,替换库,DLL 等,实现行为替换。

暴露静态方法:避免对象的实例化,用于难实例化的对象。

换函数为函数指针:用于C 的行为替换,不推荐。

                                                                                写于2008-5月


本文转自 zhenjing 博客园博客,原文链接:http://www.cnblogs.com/zhenjing/archive/2011/04/20/2021792.html   ,如需转载请自行联系原作者


相关文章
|
存储 C++
读书笔记 effective c++ Item 44 将与模板参数无关的代码抽离出来
1. 使用模板可能导致代码膨胀 使用模板是节省时间和避免代码重用的很好的方法。你不需要手动输入20个相同的类名,每个类有15个成员函数,相反,你只需要输入一个类模板,然后让编译器来为你实例化20个特定的类和300个你需要的函数。
764 0
|
安全 数据库 C++
读书笔记 effective c++ Item 29 为异常安全的代码而努力
异常安全在某种意义上来说就像怀孕。。。但是稍微想一想。在没有求婚之前我们不能真正的讨论生殖问题。 假设我们有一个表示GUI菜单的类,这个GUI菜单有背景图片。这个类将被使用在多线程环境中,所以需要mutex进行并发控制。
889 0
【读书笔记】抽象工厂模式代码
  抽象工厂模式使得她让具体的过程与客户端分离,该模式使用恰当的话会比较好的遵守 开放-封闭原则,依赖倒转原则。 不多说了,代码:/Files/cappuccino/AbstractFactory.rar UML图: 请高手多多指教。 后记:等待中但我一定要加油,坚持不懈。
703 0
|
C# C++ uml
【读书笔记】工厂方法模式代码(C#,C++)
  工厂方法模式,定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法模式克服了简单工厂模式违反开放-封闭原则的缺点,又保持了封装对象创建过程的优点,缺点是由于每加一个产品,就需要加一个产品工厂类,增加了额外的开发量。
742 0
【读书笔记】原型模式代码(C#)
今天学习了原型模式,并写了一个例子,请高手们指教 代码如下:/Files/cappuccino/PrototypeModel.rar
757 0
【读书笔记】模板方法模式代码(C++)
  模板方法模式用C++翻译过来了,代码如下/Files/cappuccino/TemplateMode.rar
640 0
|
C# C++
【读书笔记】建造者模式代码完成与大家分享
  建造者模式的好处就是隐藏了产品时如何组装产品,建造者模式主要用于一些复杂的对象,内部建造的顺序是固定的,但是每部建造的过程有很大的变化. C#代码:/Files/cappuccino/BuilderModel.
622 0
【读书笔记】策略模式代码(c#)
  今天学习了策略模式,写了个例子,与大家分享/Files/cappuccino/TacticsModel.rar
704 0
【读书笔记】将策略模式转换成C++代码
如题,下载地址如下,希望高手指教,哈 /Files/cappuccino/TacicsModelForC.rar
701 0
【读书笔记】代理模式代码(C#)
  代理模式代码,与大家分享,代码如下:/Files/cappuccino/ProxyModel.rar
672 0

相关实验场景

更多