在单元测试中,功能测试和白盒测试通常具有这样的关系:如果功能测试足够充分,那么,所有可以覆盖的白盒逻辑单位都已经覆盖,剩下的是不可覆盖的;反 过来说,如果有一些逻辑单位未覆盖,并且不能证明该逻辑单位是不可覆盖的,那么,可以认为功能测试不完整:或者等价类的划分不够准确完整,或者有些等价类 未测试到。也是说,白盒覆盖指标可以衡量功能测试的完整性,依据某个未覆盖的逻辑目标,可以发现遗漏的等价类。运行测试后,VU会自动统计白盒覆盖状 况,标示出未覆盖的代码、条件、分支及路径,并且提供测试用例设计器来帮助设计可以覆盖遗漏的逻辑单位的测试用例。只要有了第一个测试用例,测试用例设计 器能很好地工作。

  前面说过,使用VU,能达到语句、条件、分支、路径覆盖。很多读者会问,对于稍为复杂一点的程序,路径可能几百上千条,覆盖可能吗?那要耗费多少资源?

  任何程序,不管它有多复杂,都不可能脱离客观规律和客观实际。路径是什么?路径是代码的组合,是程序可能的运行路线。对于一个函数来说,只要输入确 定了,程序的运行路线确定了(局部静态变量是一个特例,它实质上是全局变量,只不过是局部可见而已,因此,也应该看作是一个输入)。从等价类的角度来 看,一个等价类里所有可能取值,一般来说覆盖的路径是一样的。我们可以大体上认为:程序的可覆盖路径的数量与等价类的数量基本相等。例如,一个程序,功能 是输入人民币小写数值,输出大写字符串,它的路径可能有几百条,但是,我们简单的想一下,会发现等价类不会超过十个,因此,大体上可以说,可以覆盖的路 径不会超过10条。

  至于语句、条件、分支,也可能有一些是不能覆盖的,这些逻辑目标的处理要比路径简单得多。我们说达到语句、条件、分支、路径覆盖,是指覆盖可以覆盖的部分,并把不能覆盖的部分识别出来并作适当的处理。

  VU的测试用例设计器具有两方面的功能:识别不可覆盖的逻辑目标,为可覆盖的逻辑目标设计测试用例。测试用例设计器的工作原理是:从现有的测试用例中 计算出一个接近于可覆盖预期逻辑目标的用例作为近似用例,并生成修改提示,依据修改提示对近似测试用例的一个或多个输入数据(通常是一个)进行修改,并 视需要修改预期输出,即可获得可以覆盖预期逻辑目标的测试用例。修改提示的主要内容是已满足条件和待满足条件,已满足条件是近似测试用例已经满足的条件, 修改近似测试用例时要保证不破坏已满足条件,待满足条件是新的测试用例必须满足的条件。如果待满足条件与已满足条件不冲突,则依据待满足条件修改近似测试 用例获得新的测试用例,如果冲突,则该逻辑目标是不可覆盖的,如果条件提示难于理解,可以切换到代码模式下,查看程序逻辑。

  不可覆盖的语句或条件,一般属于冗余代码,建议删除。不可覆盖的分支或路径,则在逻辑结构图中打上删除标识,这种删除不会影响代码。

  有读者会问,如果几百上千条路径,要一条一条识别它能不能覆盖,那可能吗?这种担心是不必要的。只要按照语句覆盖、条件覆盖、分支覆盖、路径覆盖的顺 序来完成逻辑覆盖,工作量通常都很小,原因是可确认的不可覆盖的路径会自动剔除。例如,如果一条分支不可覆盖,那么所有“经过”这条分支的路径也肯定不可 覆盖,把一条分支删除了,所有“经过”该分支的路径都会自动删除,所以,在完成语句、条件、分支覆盖后(包括把不可覆盖的分支删除),路径数量不会是庞 大的了,未覆盖路径则更少。

  对于复杂的程序,还可以在逻辑结构图中屏蔽一些安全的分支结构。有一些代码形成的分支结构,对其后的程序的逻辑并无影响。例如:

void Find(CString& str, char ch, int start=0, int end=-1)

{

if(end == -1)

end = str.GetLength();

......

}

  上列的if结构形成的分支结构只用于处理缺省值参数,对后面的代码逻辑无影响,因此是安全的。在逻辑结构图中,与一个复杂的分支结构并列的一个或多个简单 的分支结构,通常都是安全的,可以在逻辑结构图中查看各个分支结构对应的代码以判断该分支结构是否安全。安全的分支结构可以屏蔽,以便把注意力集中到值得 关注的部分。屏蔽安全的分支结构也会使路径的数量大幅度减少。前面所说的人民币小写转大小的程序,在删除了不可覆盖分支,屏蔽了安全的分支结构后,路径只 剩下不到十条,与等价类的数量是接近的。