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


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

 

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


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

  {

  if(end == -1)


  end = str.GetLength();

 

  ......

  }

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

  边界测试


  在测试用例部分已经说过,设计测试用例时要考虑边界输入和非法输入,这里统称为特殊输入,程序员在编写代码时也要考虑特殊输入,要为特殊输入编写处理代 码。在实际工作中,程序员没有考虑到某些特殊输入是很常见的,这也是程序错误的一个重要来源。不幸的是,如果编写代码和建立测试用例时都没有考虑这些输 入,那么白盒覆盖也不能自动发现,因为白盒覆盖是以代码为基础的,如果相应的代码根本不存在,白盒覆盖当然不会告诉用户“某某代码未覆盖”。

 

  特殊输入通常与数据类型有关,例如,如果一个参数是指针,空指针是一个特殊输入,对于一个整数类型,大值、小值、0、1、-1都可以算是特殊输 入;另一方面,当输入特殊数据时,如果程序未作合适的处理,运行结果常常是产生异常。根据这两个条件,如果预先为各个数据类型定义特殊值,然后由测试工具 自动生成测试用例,使用这些特殊值或其组合作为输入数据进行测试,通常可以发现“未处理特殊输入”而产生的程序错误,这是边界测试。

  如果在边界测试中发现了处理某些特殊输入的代码缺失,应补充这些代码,并完成白盒覆盖。

  为了进一步说明测试完整性,举个例子:假如一个函数,大概有十个等价类,但这个数字并不是显式的,测试人员比较容易想到的,可能只有五个,自己画一下逻辑 结构图,做一些代码分析,也许又可以找到二三个,是不是齐全了呢?很难衡量。使用VU,设计测试用例的过程大体是这样的:用户为容易想到的五个等价类建立 测试用例,根据语句、条件、分支覆盖,在测试用例设计器的帮助下,找到另两个等价类,根据路径覆盖,又揪出了两个很隐秘的等价类,实现了语句、条 件、分支、路径覆盖,后,边界测试又发现了一个意料之外的等价类。当然,这些数字只是一个示意,实现某某覆盖的目的,并不在于覆盖率,而在于尽可能找出 所有等价类。

  如果针对代码单元的测试完成了语句、条件、分支、路径覆盖,并且执行了边界测试,虽然仍然不能证明所有的等价类都测试到了,但可以肯定的说, 已经达到了很高的测试完整性,局部代码中仍然含有错误的可能性很小,当然,设计上的错误除外,这不属于单元测试的范畴。

  回归测试

 

  在修改了代码后,可以使用回归测试,对选定的任何类或整个工程执行测试,以检测修改是否破坏了现有代码的功能。一般来说,修改了私有函数,要运行整个类的测试,修改了公有或保护函数,则要运行整个工程的测试。