首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

追求代码质量 不要被覆盖报告所迷惑(5)

追求代码质量 不要被覆盖报告所迷惑(5)

条件带来的麻烦[size=1.0625]正如您已经知道的,代码中的许多变量可能有多种状态;此外,条件的存在使得执行有多条路径。在留意这些问题之后,我将在清单 5 中定义一个极其简单只有一个方法的类:
清单 5.您能看出下面的缺陷吗?

[size=0.875]1


[size=0.875]2


[size=0.875]3


[size=0.875]4


[size=0.875]5


[size=0.875]6


[size=0.875]7


[size=0.875]8


[size=0.875]9


[size=0.875]10


[size=0.875][size=0.875]package com.vanward.coverage.example01;
[size=0.875]public class PathCoverage {
[size=0.875]  public String pathExample(boolean condition){
[size=0.875]    String value = null;
[size=0.875]    if(condition){
[size=0.875]      value = " " + condition + " ";
[size=0.875]    }
[size=0.875]    return value.trim();
[size=0.875]  }
[size=0.875]}




[size=1.0625]您是否发现了清单 5 中有一个隐藏的缺陷呢?如果没有,不要担心,我会在清单 6 中写一个测试案例来执行 pathExample() 方法并确保它正确地工作:
清单 6. JUnit 来救援!

[size=0.875]1


[size=0.875]2


[size=0.875]3


[size=0.875]4


[size=0.875]5


[size=0.875]6


[size=0.875]7


[size=0.875]8


[size=0.875]9


[size=0.875]10


[size=0.875][size=0.875]package test.com.vanward.coverage.example01;
[size=0.875]import junit.framework.TestCase;
[size=0.875]import com.vanward.coverage.example01.PathCoverage;
[size=0.875]public class PathCoverageTest extends TestCase {
[size=0.875]  public final void testPathExample() {
[size=0.875]    PathCoverage clzzUnderTst = new PathCoverage();
[size=0.875]    String value = clzzUnderTst.pathExample(true);
[size=0.875]    assertEquals("should be true", "true", value);
[size=0.875]  }
[size=0.875]}




[size=1.0625]我的测试案例正确运行,我的神奇的代码覆盖报告(如下面图 3 所示)使我看上去像个超级明星,测试覆盖率达到了 100%!
图 3. 覆盖率明星[size=1.0625]我想现在应该到饮水机边上去说了,但是等等,我不是怀疑代码中有什么缺陷呢?认真检查清单 5 会发现,如果 condition 为 false,那么第 13 行确实会抛出 NullPointerException。Yeesh,这儿发生了什么?
[size=1.0625]这表明行覆盖的确不能很好地指示测试的有效性。
路径的恐怖[size=1.0625]在清单 7 中,我定义了另一个包含 indirect 的简单例子,它仍然有不能容忍的缺陷。请注意 branchIt()方法中 if 条件的后半部分。(HiddenObject 类将在清单 8 中定义。)
清单 7. 这个代码足够简单

[size=0.875]1


[size=0.875]2


[size=0.875]3


[size=0.875]4


[size=0.875]5


[size=0.875]6


[size=0.875]7


[size=0.875]8


[size=0.875]9


[size=0.875]10


[size=0.875]11


[size=0.875]12


[size=0.875]13


[size=0.875]14


[size=0.875]15


[size=0.875]16


[size=0.875]17


[size=0.875]18


[size=0.875][size=0.875]package com.vanward.coverage.example02;
[size=0.875]import com.acme.someotherpackage.HiddenObject;
[size=0.875]public class AnotherBranchCoverage {
[size=0.875]   
[size=0.875]  public void branchIt(int value){
[size=0.875]    if((value > 100) || (HiddenObject.doWork() == 0)){
[size=0.875]      this.dontDoIt();
[size=0.875]    }else{
[size=0.875]      this.doIt();
[size=0.875]    }
[size=0.875]  }                             
[size=0.875]  private void dontDoIt(){
[size=0.875]    //don't do something...
[size=0.875]  }
[size=0.875]  private void doIt(){
[size=0.875]    //do something!
[size=0.875]  }   
[size=0.875]}




[size=1.0625]呀!清单 8 中的 HiddenObject 是有害的。与清单 7 中一样,调用 doWork() 方法会导致 RuntimeException:
清单 8. 上半部分!

[size=0.875]1


[size=0.875]2


[size=0.875]3


[size=0.875]4


[size=0.875]5


[size=0.875]6


[size=0.875]7


[size=0.875][size=0.875]package com.acme.someotherpackage.HiddenObject;
[size=0.875]public class HiddenObject {
[size=0.875]  public static int doWork(){
[size=0.875]    //return 1;
[size=0.875]    throw new RuntimeException("surprise!");
[size=0.875]  }
[size=0.875]}




[size=1.0625]但是我的确可以通过一个良好的测试捕获这个异常!在清单 9 中,我编写了另一个好的测试,以图挽回我的超级明星光环:
清单 9. 使用 JUnit 规避风险

[size=0.875]1


[size=0.875]2


[size=0.875]3


[size=0.875]4


[size=0.875]5


[size=0.875]6


[size=0.875]7


[size=0.875]8


[size=0.875]9


[size=0.875]10


[size=0.875][size=0.875]package test.com.vanward.coverage.example02;
[size=0.875]import junit.framework.TestCase;
[size=0.875]import com.vanward.coverage.example02.AnotherBranchCoverage;
[size=0.875]public class AnotherBranchCoverageTest extends TestCase {
[size=0.875]     
[size=0.875]  public final void testBranchIt() {
[size=0.875]    AnotherBranchCoverage clzzUnderTst = new AnotherBranchCoverage();
[size=0.875]    clzzUnderTst.branchIt(101);
[size=0.875]  }   
[size=0.875]}




[size=1.0625]您对这个测试案例有什么想法?您也许会写出更多的测试案例,但是请设想一下清单 7 中不确定的条件有不止一个的缩短操作会如何。设想如果前半部分中的逻辑比简单的 int 比较更复杂,那么 需要写多少测试案例才能满意?
山不在高,有仙则名;水不在深,有龙则灵。
返回列表