Junit测试(转载)

@Test(timeout=1000)

publicvoidselfXMLReader(){

……

}

忽略测试方法

JUnit提供注解org.junit.Ignore用于暂时忽略某个测试方法,因为有时候由于测试环境受限,并不能保证每一个测试方法都能正确运行。例如下面的代码便表示由于没有了数据库链接,提示JUnit忽略测试方法unsupportedDBCheck:

@Ignore(“dbisdown”)

@Test(expected=UnsupportedDBVersionException.class)

publicvoidunsupportedDBCheck(){

……

}

但是一定要小心。注解org.junit.Ignore只能用于暂时的忽略测试,如果需要永远忽略这些测试,一定要确认被测试代码不再需要这些测试方法,以免忽略必要的测试点。

测试运行器

又一个新感念出现了——测试运行器,JUnit中所有的测试方法都是由它负责执行的。JUnit为单元测试提供了默认的测试运行器,但JUnit并没有限制您必须使用默认的运行器。相反,您不仅可以定制自己的运行器(所有的运行器都继承自org.junit.runner.Runner),而且还可以为每一个测试类指定使用某个具体的运行器。指定方法也很简单,使用注解org.junit.runner.RunWith在测试类上显式的声明要使用的运行器即可:

@RunWith(CustomTestRunner.class)

publicclassTestWordDealUtil{

……

}

显而易见,如果测试类没有显式的声明使用哪一个测试运行器,JUnit会启动默认的测试运行器执行测试类(比如上面提及的单元测试代码)。一般情况下,默认测试运行器可以应对绝大多数的单元测试要求;当使用JUnit提供的一些高级特性(例如即将介绍的两个特性)或者针对特殊需求定制JUnit测试方式时,显式的声明测试运行器就必不可少了。

测试套件

在实际项目中,随着项目进度的开展,单元测试类会越来越多,可是直到现在我们还只会一个一个的单独运行测试类,这在实际项目实践中肯定是不可行的。为了解决这个问题,JUnit提供了一种批量运行测试类的方法,叫做测试套件。这样,每次需要验证系统功能正确性时,只执行一个或几个测试套件便可以了。测试套件的写法非常简单,您只需要遵循以下规则:

创建一个空类作为测试套件的入口。

使用注解org.junit.runner.RunWith和org.junit.runners.Suite.SuiteClasses修饰这个空类。

将org.junit.runners.Suite作为参数传入注解RunWith,以提示JUnit为此类使用套件运行器执行。

将需要放入此测试套件的测试类组成数组作为注解SuiteClasses的参数。

 保证这个空类使用public修饰,而且存在公开的不带有任何参数的构造函数。

packagecom.ai92.cooljunit;

importorg.junit.runner.RunWith;

importorg.junit.runners.Suite;

……

/**

*批量测试工具包中测试类

*@authorAi92

*/

@RunWith(Suite.class)

@Suite.SuiteClasses({TestWordDealUtil.class})

publicclassRunAllUtilTestsSuite{

}

上例代码中,我们将前文提到的测试类TestWordDealUtil放入了测试套件RunAllUtilTestsSuite中,在Eclipse中运行测试套件,可以看到测试类TestWordDealUtil被调用执行了。测试套件中不仅可以包含基本的测试类,而且可以包含其它的测试套件,这样可以很方便的分层管理不同模块的单元测试代码。但是,您一定要保证测试套件之间没有循环包含关系,否则无尽的循环就会出现在您的面前……。

参数化测试

回顾一下我们在小节“JUnit初体验”中举的实例。为了保证单元测试的严谨性,我们模拟了不同类型的字符串来测试方法的处理能力,为此我们编写大量的单元测试方法。可是这些测试方法都是大同小异:代码结构都是相同的,不同的仅仅是测试数据和期望值。有没有更好的方法将测试方法中相同的代码结构提取出来,提高代码的重用度,减少复制粘贴代码的烦恼?在以前的JUnit版本上,并没有好的解决方法,而现在您可以使用JUnit提供的参数化测试方式应对这个问题。

参数化测试的编写稍微有点麻烦(当然这是相对于JUnit中其它特性而言):

为准备使用参数化测试的测试类指定特殊的运行器org.junit.runners.Parameterized。

为测试类声明几个变量,分别用于存放期望值和测试所用数据。

为测试类声明一个使用注解org.junit.runners.Parameterized.Parameters修饰的,返回值为java.util.Collection的公共静态方法,并在此方法中初始化所有需要测试的参数对。

为测试类声明一个带有参数的公共构造函数,并在其中为第二个环节中声明的几个变量赋值。

编写测试方法,使用定义的变量作为参数进行测试。

我们按照这个标准,重新改造一番我们的单元测试代码:

packagecom.ai92.cooljunit;

importstaticorg.junit.Assert.assertEquals;

importjava.util.Arrays;

importjava.util.Collection;

importorg.junit.Test;

importorg.junit.runner.RunWith;

importorg.junit.runners.Parameterized;

importorg.junit.runners.Parameterized.Parameters;

@RunWith(Parameterized.class)

publicclassTestWordDealUtilWithParam{

privateStringexpected;

privateStringtarget;

@Parameters

publicstaticCollectionwords(){

  returnArrays.asList(newObject[][]{

   {"employee_info","employeeInfo"},    //测试一般的处理情况

   {null,null},              //测试null时的处理情况

   {"",""},                //测试空字符串时的处理情况

   {"employee_info","EmployeeInfo"},    //测试当首字母大写时的情况

   {"employee_info_a","employeeInfoA"},  //测试当尾字母为大写时的情况

   {"employee_a_info","employeeAInfo"}  //测试多个相连字母大写时的情况

  });

}

/**

*参数化测试必须的构造函数

*@paramexpected  期望的测试结果,对应参数集中的第一个参数

*@paramtarget  测试数据,对应参数集中的第二个参数

*/

publicTestWordDealUtilWithParam(Stringexpected,Stringtarget){

this.expected=expected;

this.target=target;

}

/**

*测试将Java对象名称到数据库名称的转换

*/

@TestpublicvoidwordFormat4DB(){

assertEquals(expected,WordDealUtil.wordFormat4DB(target));

}

}

 很明显,代码瘦身了。在静态方法words中,我们使用二维数组来构建测试所需要的参数列表,其中每个数组中的元素的放置顺序并没有什么要求,只要和构造函数中的顺序保持一致就可以了。现在如果再增加一种测试情况,只需要在静态方法words中添加相应的数组即可,不再需要复制粘贴出一个新的方法出来了。

JUnit和Ant

随着项目的进展,项目的规模在不断的膨胀,为了保证项目的质量,有计划的执行全面的单元测试是非常有必要的。但单靠JUnit提供的测试套件很难胜任这项工作,因为项目中单元测试类的个数在不停的增加,测试套件却无法动态的识别新加入的单元测试类,需要手动修改测试套件,这是一个很容易遗忘得步骤,稍有疏忽就会影响全面单元测试的覆盖率。

当然解决的方法有多种多样,其中将JUnit与构建利器Ant结合使用可以很简单的解决这个问题。Ant——备受赞誉的Java构建工具。它凭借出色的易用性、平台无关性以及对项目自动测试和自动部署的支持,成为众多项目构建过程中不可或缺的独立工具,并已经成为事实上的标准。Ant内置了对JUnit的支持,它提供了两个Task:junit和junitreport,分别用于执行JUnit单元测试和生成测试结果报告。使用这两个Task编写构建脚本,可以很简单的完成每次全面单元测试的任务。

不过,在使用Ant运行JUnit之前,您需要稍作一些配置。打开Eclipse首选项界面,选择Ant->Runtime首选项(见图7),将JUnit4.1的JAR文件添加到ClasspathTab页中的GlobalEntries设置项里。记得检查一下AntHomeEntries设置项中的Ant版本是否在1.7.0之上,如果不是请替换为最新版本的AntJAR文件。

图7AntRuntime首选项

剩下的工作就是要编写Ant构建脚本build.xml。虽然这个过程稍嫌繁琐,但这是一件一劳永逸的事情。现在我们就把前面编写的测试用例都放置到Ant构建脚本中执行,为项目coolJUnit的构建脚本添加一下内容:

<?xmlversion="1.0"?>

<!--=============================================

autounittesttask  

ai92                                

==========================================-->

<projectname="autounittesttask"default="junitandreport"basedir=".">

<propertyname="outputfolder"value="bin"/>

<propertyname="srcfolder"value="src"/>

<propertyname="testfolder"value="testsrc"/>

<propertyname="reportfolder"value="report"/>

<!-------------------

 target:testreportfolderinit           

------------------->

<targetname="testinit">

<mkdirdir="${reportfolder}"/>

</target>

<!-------------------

 target:compile           

------------------->

<targetname="compile">

<javacsrcdir="${srcfolder}"destdir="${outputfolder}"/>

<echo>compilationcomplete!</echo>

</target>

<!-------------------

 target:compiletestcases           

------------------->

<targetname="testcompile"depends="testinit">

<javacsrcdir="${testfolder}"destdir="${outputfolder}"/>

<echo>testcompilationcomplete!</echo>

</target>

<targetname="allcompile"depends="compile,testcompile">

</target>

<!--========================================

 target:autotestalltestcaseandoutputreportfile           

 =====================================-->

<targetname="junitandreport"depends="allcompile">

<junitprintsummary="on"fork="true"showoutput="true">

  <classpath>

    <filesetdir="lib"includes="**/*.jar"/>

    <pathelementpath="${outputfolder}"/>

  </classpath>

  <formattertype="xml"/>

  <batchtesttodir="${reportfolder}">

    <filesetdir="${outputfolder}">

      <includename="**/Test*.*"/>

    </fileset>

  </batchtest>

</junit>

<junitreporttodir="${reportfolder}">

  <filesetdir="${reportfolder}">

    <includename="TEST-*.xml"/>

  </fileset>

  <reportformat="frames"todir="${reportfolder}"/>

</junitreport>

</target>

</project>

Targetjunitreport是Ant构建脚本中的核心内容,其它target都是为它的执行提供前期服务。Taskjunit会寻找输出目录下所有命名以“Test”开头的class文件,并执行它们。紧接着Taskjunitreport会将执行结果生成HTML格式的测试报告(图8)放置在“reportfolder”下。

为整个项目的单元测试类确定一种命名风格。不仅是出于区分类别的考虑,这为Ant批量执行单元测试也非常有帮助,比如前面例子中的测试类都已“Test”打头,而测试套件则以“Suite”结尾等等。

图8junitreport生成的测试报告

现在执行一次全面的单元测试变得非常简单了,只需要运行一下Ant构建脚本,就可以走完所有流程,并能得到一份详尽的测试报告。您可以在Ant在线手册中获得上面提及的每一个Ant内置task的使用细节。

总结

随着越来越多的开发人员开始认同并接受极限编程(XP)的思想,单元测试的作用在软件工程中变得越来越重要。本文旨在将最新的单元测试工具JUnit4介绍给您,以及如何结合IDEEclipse和构建工具Ant创建自动化单元测试方案。并且还期望您能够通过本文“感染”一些好的单元测试意识,因为JUnit本身仅仅是一份工具而已,它的真正优势来自于它的思想和j技术

相关推荐