|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
首先java功能强大的背后是其复杂性,就拿web来说,当今流行的框架有很多,什么struts,spring,jQuery等等,而这无疑增加了java的复杂性。
本文将先容两种开辟理论,用于进步Java单位测试中的代码掩盖率。代码掩盖率=(被测代码/代码总数)*100%。进步被测代码数目或下降代码总数,都可到达进步代码掩盖率的效果。在本文中,您将看到怎样经由过程利用反射机制,在内部间接对方针类中的不成会见成员举行测试,以进步被测代码数目;和经由过程修正Cobertura源码,使其撑持经由过程正则表达式来过滤不必要举行单位测试的代码,以下降代码总数。代码掩盖率的进步,削减了单位测试过程当中未被掩盖的代码数目,下降了开辟职员编写或修正单位测试用例的工夫本钱,从而进步了全部单位测试的效力。
弁言
单位测试是软件开辟过程当中主要的质量包管环节。单位测试能够削减代码中潜伏的毛病,使缺点更早地被发明,从而下降了软件的保护本钱。软件代码的质量由单位测试来包管,而单位测试本身的质量与效力成绩也不容无视。进步单位测试的质量与效力,不但可以使软件代码加倍有包管,并且可以节俭开辟职员编写大概修正单位测试代码的工夫。权衡单位测试质量与效力的目标多种多样,代码掩盖率是个中一个极其主要的目标。一样平常而言,代码掩盖率越高,单位测试掩盖的局限就越年夜,代码中潜伏毛病的数目就越少,软件质量就越高。本文起首先容代码掩盖率的统计目标范例及经常使用统计工具,然后重点拔取具有代表性的行掩盖率举行剖析,先容两种办法用于进步代码的行掩盖率。
代码掩盖率的统计目标
代码掩盖率指的是一种权衡代码掩盖水平的体例,一般会对以下几种体例举行统计剖析:
- 行掩盖。它又被称作语句掩盖或基础块掩盖。这是一种较为经常使用且具有代表性的目标,器度的是被测代码中每一个可实行语句是不是被实行到。
- 前提掩盖。它器度的是今世码中存在分支时,是不是能掩盖进进分支和不进进分支这两种情形。这请求开辟职员编写多个测试用例以分离满意进进分支与不进进分支这两种情形。
- 路径掩盖。它器度的是今世码中存在多个分支时,是不是掩盖到分支之间分歧组合体例所发生的全体路径。这是一种力度最强的掩盖检测,绝对而言,前提掩盖只是路径掩盖中的一部分。
在这三种掩盖目标中,行掩盖复杂,合用性广,但大概会被以为是“最弱的掩盖”,实在否则。行掩盖相对前提或路径掩盖,可使开辟职员经由过程尽量少的测试数据和用例,掩盖尽量多的代码。一般情形下,是先经由过程工具检测一遍全部工程单位测试的行掩盖情形,然后针对没有被掩盖到的代码,剖析其没有被掩盖到的缘故原由。假如是因为该代码地点分支因为不满意进进该分支的前提而没有被掩盖,那末开辟职员才会进一步修正或增添测试代码,完成该部分的前提或路径掩盖。
可见,高效高质量的行掩盖是无效举行前提掩盖与路径掩盖的条件。行掩盖率越高,申明没有被掩盖到的代码越少,如许开辟职员便会合中精神修正测试用例,掩盖这些数目未几的代码。相反,假如行掩盖率低,开辟职员必要逐一反省没有被掩盖到的代码,精神被分离,因而很难进步残剩代码单位测试的质量。
代码掩盖率=被测代码行数/参测代码总行数*100%。从代码掩盖率的盘算体例中能够看出,要进步代码掩盖率,可经由过程进步被测代码行数,或削减参测代码总行数的体例举行。以下将会从这两个角度分离动手,剖析怎样进步被测代码行数及削减参测代码总行数。
利用Cobertura统计并进步代码的行掩盖率
Cobertura是一款优异的开源测试掩盖率统计工具,它与单位测试代码分离,标志并剖析在测试包运转时实行了哪些代码和没有实行哪些代码和所经由的前提分支,来丈量测试掩盖率。除找出未测试到的代码并发明bug外,Cobertura还能够经由过程标志无用的、实行不到的代码来优化代码,终极天生一份美妙细致的HTML掩盖率检测呈报。
Cobertura基础工具包里有四个基础历程及对应的工具:cobertura-check,cobertura-instrument,cobertura-merge,cobertura-report;这个剧本自力利用较为烦琐,不便利也倒霉于主动化。不外,Cobertura在Maven编译平台上有响应的cobertura-maven-plugin插件,使代码编译、检测、集成等各个周期能够流水线式主动化完成。
Cobertura-maven-plugin官方版有五个次要方针指令(goal),如表1:
表1.Cobertura方针指令及感化注释
方针指令感化注释Cobertura:check反省最初一次标注(instrumentation)准确与否Cobertura:clean清算插件临盆的两头及终极呈报文件Cobertura:dump-datafileCobertura数据文件dump指令,不经常使用Cobertura:instrument标注编译好的javaclass文件Cobertura:cobertura标注、运转测试并发生Cobertura掩盖率呈报Cobertura一般会与Maven一同利用。因而工程目次布局假如遵守Maven保举的尺度的话,一个集成Cobertura的基础POM文件如清单1所示:
清单1.POM文件的基础布局
- <project><reporting><plugins><plugin><!--此处用于将Cobertura插件集成到Maven中--><groupId>org.codehaus.mojo</groupId><artifactId>cobertura-maven-plugin</artifactId><version>2.5.2</version></plugin></plugins></reporting></project>
复制代码 假如工程目次布局没有接纳Maven保举尺度,则必要举行以下分外设置:
清单2.合适Maven的工程目次布局设置
- <build><!--Java源代码的路径设置--><sourceDirectory>src/main/java</sourceDirectory><scriptSourceDirectory>src/main/scripts</scriptSourceDirectory><!--测试代码的路径设置--><testSourceDirectory>src/test/java</testSourceDirectory><!--源码编译后的class文件的路径设置--><outputDirectory>target/classes</outputDirectory><!--测试源码编译后的class文件的路径设置--><testOutputDirectory>target/test-classes</testOutputDirectory><plugin>....</plugin></build>
复制代码 单位测试代码编写完成,一切设置配制好后,在工程根目次运转“mvncobertura:cobertura”Maven就会对代码举行编译。编译完成以后,就会在项目中运转测试代码并输入测试呈报了局到目次project_base$targetsitecoberturaindex.html,效果如所示。
.Cobertura掩盖剖析呈报
<br>
从以上呈报中可见,
- 代码全体的行掩盖率其实不高,有些包或类掩盖率很低,乃至为0。思索到这些包或类的特别性(比方它们已被其他类代替),无需对它们举行单位测试,因而必要从全部测试局限中剔除。
- 部分类的行掩盖率固然已靠近100%,但仍存在一些办法(如set和get办法)因为没有测试的需要却被列进了统计局限,这些办法必要被过滤失落。
针对上述两种改善措施,都可使用Cobertura举行完成。第一种改善措施Cobertura能够撑持,而第二改善措施则必要对Cobertura源码举行修正,重编译前方可撑持。上面将具体先容怎样利用Cobertura对上述成绩举行优化。
过滤不需举行单位测试的包和类
针对项目中不需举行单位测试的包和类,我们能够使用POM文件中Cobertura的标注(instrument)设置,对响应的包和类举行剔除(exclude)或选择(include),使之不表现在掩盖率呈报中,往除它们对全部掩盖率的影响,从而使呈报更具针对性。其基础POM标签设置及剖析如清单3中所示。
清单3.POM中剔除包和类的设置示例
- <configuration><instrumentation><excludes><!--此处用于指定哪些类会从单位测试的统计局限中被剔除--><exclude>exs/res/process/egencia/Mock*.class</exclude><exclude>exs/res/process/test/**/*Test.class</exclude></excludes></instrumentation></configuration><executions><execution><goals><goal>clean</goal></goals></execution></executions>
复制代码 经由过程在设置文件中利用Include与Exclude,能够显式地指定哪些包和类被列进单位测试的统计局限,哪些包和类被剔除在此局限以外。正则表达式撑持丰厚的婚配前提,能够满意年夜多半项目对单位测试局限的请求。以上代码将exs.res.process.egencia上面一切的称号Mock开首的类,和exs.res.process.egencia.test包上面以Test开头的类都剔除在测试局限之外。在利用这类设置以后,代码全体的局限被减少,因而在被掩盖到的代码数目稳定的基本上,全部代码掩盖率会较之前进步。输入了局如所示。
.包、类过滤效果
<br>
过滤类中的函数
最新版本中的Cobertura只能撑持到类级其余过滤,而关于类中办法的过滤是不撑持的。因而我们必要经由过程修正Cobertura源码,使Cobertura撑持对类中办法的过滤。
对Cobertura及其插件修改所根据的次要道理是:修正Cobertura-maven-plugin项目中的InstrumentationTask类,增添Ignoretrival,IgnoreMethod等新增POM参数。配制正则表达式,修正Cobertura中心,在标注(instrumentation)阶段遍历函数名时,检测函数名是不是婚配传进的正则表达式,过滤函数体代码,从而把这些函数代码扫除在代码掩盖统计以外,节俭开辟职员对这类代码的测试精神。
清单4至清单6是对Cobertura的几处中心修改,仅供读者参考。
清单4.对Cobertura中心代码的修改之一
- privatevoidcheckForTrivialSignature(){Type[]args=Type.getArgumentTypes(myDescriptor);Typeret=Type.getReturnType(myDescriptor);if(myName.equals("<init>")){isInit=true;mightBeTrivial=true;return;}if(myName.startsWith("set")&&args.length==1&&ret.equals(Type.VOID_TYPE)){isSetter=true;mightBeTrivial=true;return;}if((myName.startsWith("get")||myName.startsWith("is")||myName.startsWith("has"))&&args.length==0&&!ret.equals(Type.VOID_TYPE)){isGetter=true;mightBeTrivial=true;return;}}
复制代码 清单5.对CoberturaMavenplugin的修改
- privateStringignoreMethodAnnotation;privateStringignoreTrivial;/***创立一个新的对象,用于举行设置。*/publicConfigInstrumentation()/****该办法用于设置annotation的名字以用于过滤类外部的办法*@paramignoreMethodAnnotation*/publicvoidsetIgnoreMethodAnnotation(StringignoreMethodAnnotation){this.ignoreMethodAnnotation=ignoreMethodAnnotation;}publicStringgetIgnoreTrivial(){returnignoreTrivial;}/***该办法用于标识测试类中的办法是不是可有可无不必要测试。*@paramignoreTrivial*/publicvoidsetIgnoreTrivial(StringignoreTrivial){this.ignoreTrivial=ignoreTrivial;}
复制代码 清单6.POM文件中利用修正后的Cobertura过滤类中的办法
- <reporting><plugins><plugin><groupId>org.codehaus.mojo</groupId><artifactId>cobertura-maven-plugin</artifactId><version>2.5.2</version><configuration><ignores><!--经由修正的cobertura,撑持办法级其余过滤--><ignore>*main*</ignore><!--以上修正指的是过滤项目中一切类中的办法名中含有main的办法--></ignores><IgnoreTrival>true</IgnoreTrival></configuration></plugin></plugins></reporting>
复制代码 以上修正都完成以后,就能够运转“mvn:site”命令失掉呈报。是利用没有被修正的Cobertura发生的了局呈报,无函数过滤效果。是利用被修正后的Cobertura发生的了局呈报,能够从中看出,几个set与get办法已被扫除在统计局限以外。
.无函数名过滤效果
<br>
.增添函数过滤效果
<br>
回页首
使用Java反射(Reflection)机制进步代码的行掩盖率
分歧的人对反射有分歧的了解,年夜部分人认同的一种概念是:反射使得程序能够反省本身布局和软件情况,而且依据程序检测到的实践情形改动举动。
为了完成自检,一段程序必要有些信息来暗示本身,这些信息就称为元数据(metadata)。Java运转过程当中对这些元数据的自检称为内省(introspection)。内省历程以后常常举行举动改动。总的来讲,反射API使用以下三种手艺来完成举动改动:
- 间接修正元数据。
- 使用元数据举行操纵。
- 调停(Intercession),代码被同意在程序各类运转期举行调剂。
Java言语反射机制供应一组丰厚的API函数来操纵元数据,且供应了少部分主要的API来完成Intercession才能。
实践项目中,为了包管软件代码的全体质量,单位测试不但要掩盖类的私有成员,还要掩盖主要的公有成员。而有些公有成员的挪用,会被放进到极其庞大的前提分支中。而机关进进这个公有办法的相干前提,大概必要开辟职员编写大批测试代码及测试数据。这无疑增添了单位测试的本钱。偶然为了节俭本钱,该类公有办法便跳过意外,从而在有形中下降了代码的行掩盖率,影响了软件的全体质量。
而使用反射的一系列特征,我们能够在不改动源代码的情形下,间接对庞大的公有办法举行单位测试,无需增添行掩盖反省中被掩盖的代码行数,从而能够在不增添单位测试本钱的条件下,进步代码的行掩盖率与单位测试的全体质量。
清单7给出了一段复杂的方针测试代码示例。
清单7.方针测试代码示例
- packageexs.res.util;publicclassCustomer{privateStringmessage;publicStringgreet;privateStringsayHello(){return"Hello";}publicStringpHello(){return"pHello";}}
复制代码 为了测试公有函数sayHello(),使用反射元数据操纵API的测试代码为:
清单8.使用反射元数据操纵API的测试代码
- @TestpublicvoidprivateMethodTest(){finalMethodmethods[]=Customer.class.getDeclaredMethods();for(inti=0;i<methods.length;++i){if("sayHello".equals(methods[i].getName())){//这里会将sayHello办法由private变成public,从而能够间接被内部对象会见methods[i].setAccessible(true);try{StringanotherString=(String)methods[i].invoke(newCustomer(),newObject[0]);assertTrue("Hello".equalsIgnoreCase(anotherString));}catch(Exceptione){e.printStackTrace();}break;}}}@TestpublicvoidprivateFieldTest()throwsNoSuchFieldException,SecurityException{try{Fieldmessage=Customer.class.getDeclaredField("message");CustomertestCustomer=newCustomer();//这里会将message属性由private变成public,从而能够间接被内部对象会见message.setAccessible(true);message.set(testCustomer,"newMessage");assertTrue("newMessage".equalsIgnoreCase((String)message.get(testCustomer)));}catch(Exceptione){e.printStackTrace();}}
复制代码 运转以上单位测试用例来分离对Customer的公有办法sayHello和公有属性message举行间接会见,了局如所示。
.非私有函数测试效果
<br>
从图中我们能够看到Customer成员的公有办法sayHello被测试代码掩盖到。以是,当一些代码函数庞大渡过高,到经由过程机关测试数据或测试用例的办法很难使非私有成员失掉运转时,我们就能够使用Java反射机制,间接在测试类中挪用和测试方针类的非私有成员,从而进步掩盖率。
其实你不用Struts,spring这些工具,直接用jsp,servlet能够很方便地写出来,而且,可以根据个人的水平、爱好,有很多方案。而struts,spring这些工具的出来。 |
|