文章目录
物理层次结构
由依赖关系所定义的组件之间的物理层次结构,与分层所隐含的逻辑层次结构很相似。对于有效理解、维护、测试和重用来说,避免循环物理依赖是中心问题。设计良好的接口应该是短小的、易于理解和易于使用的。但是,这种接口会使用户级的测试代价惊人。
软件测试的一个比喻
当一个顾客对一个小汽车进行测试驾驶时,他主要注意小汽车作为一个整体的性能如何–小汽车的操纵、急转弯、刹车等方面怎么样。顾客对主观可用性也感兴趣–小汽车的外观是否漂亮,座位是否舒适,内饰是否豪华,总的来说就是拥有该车的满意度。一般的客户不会去测试安全气囊或者引擎安装,以了解这些部件在所有条件下运行的是否和所期望的一样。当顾客从一家著名的生产商那边购买了一个小汽车时候,会选择相信这种低层的可靠性。
小汽车若要功能正常,重要的是汽车赖以工作的每个对象也都能很好的工作。顾客不会单独地测试小汽车每一个部件–但有人会这么做。对小汽车进行质量检测不会是顾客的责任。顾客为质量好的产品付款,而质量好的一个方面就是顾客对小汽车的正常工作性能满意。
在现实世界中,小汽车的每一个部件都被设计成嗲有定义良好的接口,并且在极限条件下进行了格力测试,以保证部件在被继承进一个小汽车之前能满足指定的耐用期限。为了对汽车进行维护,机械师必须随时能够访问各种部件以便诊断和修理。
复杂的软件系统就像小汽车。所有的低层次的部件都是具有良好的定义接口的对象。没个部件或者组件爱你都可被隔离进行重点测试。通过分层技术,这些部件可以集成到一系列日益复杂的子系统中–对每个子系统都有一套测试,以保证这种增量式的继承能够正常的运行。这种分层体系结构使得测试工程师能访问在耕地抽象层次上实现的功能,而不会将低层次的接口暴露给产品的客户,最终的产品也要进行测试,以确保产品能满足客户的期望。
总的来说,一个良好的汽车是用分层的部件构造的,制造厂对这些部件进行了彻底的测试
- 在隔离的条件下
- 在一系列部分集成的子系统中
- 作为一个完全集成的产品
一旦装配完成,机械师很容易查看部件,以便进行正确的测试和维护。在软件中这些概念的本质是一样的。
一个复杂的子系统
假设:
- 一个封闭的额区域
- 在封闭区域中有一组障碍物,彼此不重叠但可以相邻,也不与该封闭区域的周界限重叠
- 一个起点和一个终点
- 宽度
确定在指定的起点和终点之间是否有一条指定宽度的直线路径存在。如果有则返回最短直线路径的中心线
测试好接口时的困难
面向对象技术的一种实际有效的应用是把极大的复杂性隐藏在一个小的、定义良好的、易于理解的和易于使用的接口后面。但是,正是这种接口会导致开发出来的子系统测试起来极其困难
例如上面的例子质保函四个公共函数:
- 一个建立封闭区域的构造函数
- 一个析构函数
- 一个在封闭区域内手机障碍物的函数
- 一个决定在区域内任意两点之间指定宽度的最短直线路径函数
回归测试指的是这样的规程:运行一个程序,比较其结果,以便检验程序从一个版本升级到另外有几个版本时是否能够继续如梭期望的那样运行
易测试性设计
质量设计的主要部分是易测试性设计,DFT的重要性在继承电路界是公认的。在许多情况相爱,只从外部管脚来测试一些IC芯片是不现实的,一些芯片有超过一百万个晶体管
对于测试来说,软件中的一个类类似于实现现实世界中的实例
对于整个设计的层次结构进行分布式测试,比只在最高层接口进行测试有效的多
隔离测试
在一个设计良好的模块化子系统中,可以对多个组件进行隔离测试。考虑到一个涉及点对点路径子系统的非常真实 的情况,该子系统最终将支持所有角度的几何形状。该系统目前暂时还处于原型阶段并且只能处理曼哈顿角。该点对点的路径系统是基于对象的,因此它在许多对象之上进行分层,这些对象目前大多数支持所有的角度。由于有些组件还没有升级为支持所以角度,所以测试本身只能用曼哈顿角度测试
独立测试降低了一部分与软件集成相关的风险
隔离测试是指这样的规程:独立于系统的其他部分对单个组件或者子系统进行的测试
隔离测试组件是确保可靠性的有效办法
隔离测试有一个关键点,过了这些关键带你,隔离测试的回报就会减少。
非循环物理依赖
对于一个能被有效测试的设计来说,一定能够将其分解成复杂性可以控制的功能单元。组件是实现此目的的理想部件。
不含循环的组件依赖图非常有利于实现易测试性,但不是所有的组件依赖图都是非循环的。
有非循环物理依赖的系统远远要比那些带有循环的系统更容易的进行有效的测试。一个系统中的㢟依赖只要是非循环的,就存在一个测试该系统的合理顺序。
层次号
层次号的起源
层次号的概念是借用数字电路、门层次、零延时电路仿真领域的概念。
每个有向非循环图都可以被赋予一个唯一的层次号,一个有循环图则不能
一个可被赋予唯一的层次号的物理依赖图成为是可层次化的
在软件中使用层次号
层次0:一个在我们的软件包之外的组件。 层次1:一个没有局部物理依赖的组件。 层次3:一个组件,它在物理上依赖于层次N-1上(但不是更高层次上)的一个组件
一个组件的层次是一个最长路径的长度,该路径是指从那个组件穿过组件依赖图到外部库组件的集合的路径
在大多数真实情况相爱,如果大型设计要被有效的测试,他们必须是可层次化的
分层次测量和增量式测试
组件是一个系统的基本构造部件。每一个组件都是不同的。每个都是物理设计模式的一个实例。表面上,他们都有相同的基本物理结构–一个物理接口(头文件)和一个物理实现(源文件)
分层次测试是指在每个物理层次结构上测试单个组件的惯例
分层测试需要为每个组件提供一个独立的测试驱动程序
增量式测试是指这样的测试管理:只测试真正在被测试组件中实现的功能
分层次方法使我们不必重新测试低层次组件的内部行为。如果我们只测试由一个特定组件添加的功能值,那么每个组件的测试复杂性就更可能保持在一个便于管理的水平上。只瞄准一个特定的组件添加的新功能的测试方式,在本书中称为增量式测试
只测试在一个组件爱你中直接实现的功能,能够使测试的复杂性与组件的复杂性相当
白盒测试是指通过查看组件底层实现来验证一个组件的期望行为
黑盒测试是指仅基于组件的规范来检测一个组件的期望行为的惯例
白盒测试检验代码工作情况是否与开发者意愿相符,与此不同,黑盒测试检验组件是否满足其需求和是否符合规范
我们希望测试的复杂性与被测试的组件的复杂性相对应。我们希望在隔离的情况下测试所有的叶子组件。测试所有高层的组件时都假设它们所依赖的低层次的组件是内部正确的。这种增量式的、分层次的策略使得我们能将测试工作集中于他能做的最好的地方,并且可以避免冗余地重新测试已经测试好的软件。
测试一个复杂的子系统
通过将组件的实现分解成独立的可测试组件的一个层次化的层次结构,我们已经为潜在地难以测试的组件的易测试性进行了设计。把测试工作分布到整个router子系统中,将指数级地减少最高层次上要获得相同质量所需的回归测试的总量。人工检测代价高昂且容易出错,由于缺少时间和资源经常不进行这种检测。但是层次化的结构使得子组件的可预测行为可以通过不需要人工干预的更健壮的方法来进行测试。
易测试性和测试
已测试性质和测试不是一码事,实际上他们在很大程度上是质量独立的两个方面。可测试的是指有一种有效的测试策略,这种策略使得我们能检测由接口描述的功能是否已经实现了。已测试的是指产品已经能被证实尊崇了他的规范。可测试性是我们从设计一开始就努力追求的目标。已测试是一种我们的产品在交给客户之前必须达到的状态。测试是我们一直在做的事情。
完全回归测试是昂贵的但也是必须得。建立彻底的回归测试的适当时间与要测试的子系统的稳定性密切相关
循环物理依赖
设计经常开始于非循环依赖,随着设计的演进,在系统功能的增强过程中,循环依赖会悄悄的混进来。
组件之间的循环物理依赖限制了组件被理解、测试和重用
避免组件之间的循环物理依赖
紧密相关的类之间相互依赖很正常,但是,这些类将完全驻留在一个单个的组件中。如果我们发现两个或者更多组件c1和c2相互依赖,我们的选择有三种:
- 对c1和c2重新打包以便他们不再相互依赖
- 将c1和c2从物理上组合成一个组件
- 将c1和c2当做一个单一的组件来考虑
累计组件依赖
现在我们通过提供一种度量标准来形式化有关设计质量方面的讨论。这种标准被称为累积组件依赖CCD。CCD与增量式回归测试的连接时开销紧密联系。更确切的说,CCD提供了一种数字表示的值,表示与开发和维护一个特定子系统有关的相对开销
累积组件依赖就是在一个子系统内的所有组件ci之上对每个组件ci增量式地测试时所需要的组件数量进行求和(即累积组件依赖就是增量式地测试子系统中所有组件所需的组件数量的总和)
C
C
D
(
N
)
=
(
组件的总数
)
∗
(
测试一个组件连接时候的开销
)
=
N
∗
N
=
N
2
(
其中
N
代表组件的数量
)
CCD(N) = (组件的总数)*(测试一个组件连接时候的开销)=N*N = N^2(其中N代表组件的数量)
CCD(N)=(组件的总数)∗(测试一个组件连接时候的开销)=N∗N=N2(其中N代表组件的数量)
非循环物理依赖可以明显减少与开发、维护和测试大型系统相关的连接时的开销
C
C
D
(
N
)
=
(
N
+
1
)
∗
(
l
o
g
2
(
N
+
1
)
−
1
)
+
1
(
其中
N
代表组件的数量
)
CCD(N)=(N+1)*(log_2(N+1)-1)+1(其中N代表组件的数量)
CCD(N)=(N+1)∗(log2(N+1)−1)+1(其中N代表组件的数量)
我们的目标是能够为每个组件建立一个测试驱动的程序,该驱动程序要测试的组件和其所依赖的组件相连接。CCD是一种测量方法,它根据与增量式地测试每个组件相关的总的连接时间来量化一个系统的耦合程度。在增量式地测试每个组件相关的总的连接时间来量化一个系统的耦合程度。在增量式地测试组件所需要的连接时间和所需要的从磁盘空间方面,循环依赖的组件展示了二次方的特性。相反,形成一个非循环的层次结构的组件依赖关系则可以极大的减少增量式组件测试的连接开销。
物理设计的质量
平均组件依赖是指一个子系统的CCD与系统中的组件数量N的比值:
A
C
D
=
C
C
D
子系统
/
N
子系统
ACD = CCD_{子系统}/N_{子系统}
ACD=CCD子系统/N子系统
CCD主要的用途是,对一个给定的体系结构较小的改动引起的整个耦合结构的变化进行量化
标准累积组件依赖是指N个组件的子系统的CCD值与相同大小的树形系统的CCD值的比值
N
C
C
D
=
C
C
D
子系统
/
C
C
D
平衡儿二叉树
(
N
子系统
)
NCCD=CCD_{子系统}/CCD_{平衡儿二叉树}(N_{子系统})
NCCD=CCD子系统/CCD平衡儿二叉树(N子系统)
使一给定组件集合的CCD最小化是一个设计目标
小结
高质量的复杂子系统由许多分层组件形成的非循环的物理层次结构组成。在系统层上进行完全测试不仅昂贵而且根本不可行–如果不是不可能–对好接口尤其如此。
一个好的接口将实现的复杂性封装在一个简单的易于使用的外表后面。同时,这使得我们通过这个接口来测试其实现异常困难。
定义一个软件系统中的类的实例与定义在该系统之外的同一个类的实例没有什么两样。我们可以利用这个事实来隔离地验证设计层次结构的各个部分。从而减少集成的部分风险。
隔离测试是确保复杂低层次组件的可靠性的一种很合算的方法。通过尽可能将测试推到设计层次结构的最底层,我们可以确保如果组件或者子系统被增强,移植或在另一个系统中重用,它将独立于客户程序而保持其指定的特性。
层次号在一个子系统内基于组件对其他组件的物理依赖来描述组件。另外,层次号给有非循环依赖组件图的系统提供了能够进行有效测试的一种顺序。若某个子系统的组件依赖形成了一个直接的非循环依赖图,则称该子系统是可层次化的。一个层次化的组件依赖图使得一个系统的物理结构更容易理解,因而也更容易维护。
分层次测试是指测试物理层次结构中的每一层的组件。每个较低层次的组件都应该提供独立于更高层次组件的良好定义的接口,并实现可被测试、验证和重用的功能
增量式测试是指单个测试驱动程序只测试被测试组件中的实际功能。在物理层次结构的耕地层次中实现的功能,此时假设为内部正确的。因此,增量式测试反应的是被测试组件的实现复杂性,而不是这个组件所依赖的组件层次结构的复杂性。增量式测试是白盒测试的一种形式,它建立在了解物理组件实现的基础上,以提高可靠性。黑河测试源于需求和组件规范,并独立于实现。这两种测试形式是相互补充的,他们都有助于保证整体质量。
易测试性是一个设计目标。循环物理依赖抑制测试、理解和重用。累计组件依赖提供了一种与增量式测试一个戈丁子系统相关的整体连接时开销的粗略数值度量。更一般地。CCD是一个给定设计的相对可维护性的一个指示器。
循环依赖设计不是可层次化的。