追求代码质量: 不要被覆盖报告所迷惑
发布时间:2006-03-10 15:35:25 来源:ibm 网友评论 0 条 条件带来的麻烦
正如您已经知道的,代码中的许多变量可能有多种状态;此外,条件的存在使得执行有多条路径。在留意这些问题之后,我将在清单 5 中定义一个极其简单只有一个方法的类:
清单 5.您能看出下面的缺陷吗?
您是否发现了清单 5 中有一个隐藏的缺陷呢?如果没有,不要担心,我会在清单 6 中写一个测试案例来执行 pathExample() 方法并确保它正确地工作:
清单 6. JUnit 来救援!
我的测试案例正确运行,我的神奇的代码覆盖报告(如下面图 3 所示)使我看上去像个超级明星,测试覆盖率达到了 100%!
图 3. 覆盖率明星
我想现在应该到饮水机边上去说了,但是等等,我不是怀疑代码中有什么缺陷呢?认真检查清单 5 会发现,如果 condition 为 false,那么第 13 行确实会抛出 NullPointerException。Yeesh,这儿发生了什么?
这表明行覆盖的确不能很好地指示测试的有效性。
路径的恐怖
在清单 7 中,我定义了另一个包含 indirect 的简单例子,它仍然有不能容忍的缺陷。请注意 branchIt() 方法中 if 条件的后半部分。(HiddenObject 类将在清单 8 中定义。)
清单 7. 这个代码足够简单
呀!清单 8 中的 HiddenObject 是有害的。与清单 7 中一样,调用 doWork() 方法会导致 RuntimeException:
清单 8. 上半部分!
但是我的确可以通过一个良好的测试捕获这个异常!在清单 9 中,我编写了另一个好的测试,以图挽回我的超级明星光环:
清单 9. 使用 JUnit 规避风险
您对这个测试案例有什么想法?您也许会写出更多的测试案例,但是请设想一下清单 7 中不确定的条件有不止一个的缩短操作会如何。设想如果前半部分中的逻辑比简单的 int 比较更复杂,那么您 需要写多少测试案例才能满意?
正如您已经知道的,代码中的许多变量可能有多种状态;此外,条件的存在使得执行有多条路径。在留意这些问题之后,我将在清单 5 中定义一个极其简单只有一个方法的类:
清单 5.您能看出下面的缺陷吗?
package com.vanward.coverage.example01; public class PathCoverage { public String pathExample(boolean condition){ String value = null; if(condition){ value = " " + condition + " "; } return value.trim(); } } |
您是否发现了清单 5 中有一个隐藏的缺陷呢?如果没有,不要担心,我会在清单 6 中写一个测试案例来执行 pathExample() 方法并确保它正确地工作:
清单 6. JUnit 来救援!
package test.com.vanward.coverage.example01; import junit.framework.TestCase; import com.vanward.coverage.example01.PathCoverage; public class PathCoverageTest extends TestCase { public final void testPathExample() { PathCoverage clzzUnderTst = new PathCoverage(); String value = clzzUnderTst.pathExample(true); assertEquals("should be true", "true", value); } } |
我的测试案例正确运行,我的神奇的代码覆盖报告(如下面图 3 所示)使我看上去像个超级明星,测试覆盖率达到了 100%!
图 3. 覆盖率明星
我想现在应该到饮水机边上去说了,但是等等,我不是怀疑代码中有什么缺陷呢?认真检查清单 5 会发现,如果 condition 为 false,那么第 13 行确实会抛出 NullPointerException。Yeesh,这儿发生了什么?
这表明行覆盖的确不能很好地指示测试的有效性。
路径的恐怖
在清单 7 中,我定义了另一个包含 indirect 的简单例子,它仍然有不能容忍的缺陷。请注意 branchIt() 方法中 if 条件的后半部分。(HiddenObject 类将在清单 8 中定义。)
清单 7. 这个代码足够简单
package com.vanward.coverage.example02; import com.acme.someotherpackage.HiddenObject; public class AnotherBranchCoverage { public void branchIt(int value){ if((value > 100) || (HiddenObject.doWork() == 0)){ this.dontDoIt(); }else{ this.doIt(); } } private void dontDoIt(){ //don't do something... } private void doIt(){ //do something! } } |
呀!清单 8 中的 HiddenObject 是有害的。与清单 7 中一样,调用 doWork() 方法会导致 RuntimeException:
清单 8. 上半部分!
package com.acme.someotherpackage.HiddenObject; public class HiddenObject { public static int doWork(){ //return 1; throw new RuntimeException("surprise!"); } } |
但是我的确可以通过一个良好的测试捕获这个异常!在清单 9 中,我编写了另一个好的测试,以图挽回我的超级明星光环:
清单 9. 使用 JUnit 规避风险
package test.com.vanward.coverage.example02; import junit.framework.TestCase; import com.vanward.coverage.example02.AnotherBranchCoverage; public class AnotherBranchCoverageTest extends TestCase { public final void testBranchIt() { AnotherBranchCoverage clzzUnderTst = new AnotherBranchCoverage(); clzzUnderTst.branchIt(101); } } |
您对这个测试案例有什么想法?您也许会写出更多的测试案例,但是请设想一下清单 7 中不确定的条件有不止一个的缩短操作会如何。设想如果前半部分中的逻辑比简单的 int 比较更复杂,那么您 需要写多少测试案例才能满意?
- 推荐阅讯
- Oracle数据安全面面观
- 创建基于AJAX技术的Scribble应用程序
- 为什么要用UML建模之建模的重要性
- 关于RSS 2.0的规范实例
- Spring入门指引之获取Spring框架
- 关于Web2.0的最后几句话
- 在定制Eclipse SWT组件中实现MVC
- Oracle数据库数据对象分析
- 解决select菜单边框无法设置的问题
- 看看如何在Struts应用中施展AJAX魔法
- 阅读排行
- 1..net页面间的参数传递简单实例
- 2.VC++与Matlab混合编程之引擎操作详解
- 3.Oracle数据库数据对象分析
- 4.Eclipse3.2+Tomcat5.5.17+Oracle9配置
- 5.Oracle数据库中索引的维护
- 6.在Oracle的网络结构中解决连接问题
- 7.Oracle数据安全面面观
- 8.Oracle数据库的ORA-00257故障解决过程
- 9.Oracle数据库备份与恢复的三种方法
- 10.Oracle与SQL Server在企业应用中的比较
- 专题教程
- Windows Server-Windows Server文档-Windows Server新闻-Windows Ser PostgreSQL-PostgreSQL文档-PostgreSQL新闻-PostgreSQL专家
- WebLogic-WebLogic文档-WebLogic新闻-WebLogic专家 FreeBSD-FreeBSD文档-FreeBSD新闻-FreeBSD专家
- Linux-内核 GUI KDE Gnome DNS FTP 安全 安装-Linux专区 Windows-AD IIS ServerCore 虚拟化 安全 HPC-Windows专区
- 大话G游 专题:手机病毒揭密
- ARP攻击防范与解决方案 路由故障处理手册
