用junit框架实现java单元测试
ReadyGo!技术成就梦想
www.efish.cn
efish
2007-9-30 19:34:07
随着软件项目的逐渐增大,软件测试在软件开发中的地位显得越来越重要。如果软件项目没有良好的测试流程,随着系统的增大,无论项目管理人员还是软件开发人员都会对项目的前景失去信心,甚至会对项目的目标产生分歧,因为长期以来没有对程序代码和系统设计进行有效的控制,很多问题都被暂时掩盖或逐渐演化成其他的问题。软件开发周期越长,就会使得问题进化的版本越多,最后造成的结果是“剪不断,理还乱”。
单元测试是整个测试流程中最基础的部分,它们要求程序员尽可能早地发现问题,并给予控制,这是其一。另外,如果集成测试出现问题,它们可以帮助诊断。这样就为在软件开发流程中建立高效的事件反应机制打下了坚实基础。
junit就是为java程序开发者实现单元测试提供一种框架,使得java单元测试更规范有效,并且更有利于测试的集成。
junit的内部结构
junit的软件结构
junit 共有七个包,核心的包就是junit.framework 和junit.runner。framework包负责整个测试对象的构架,runner负责测试驱动。
junit的类结构
junit有四个重要的类:testsuite、testcase、testresult、testrunner。前三个类属于framework包,后一个类在不同的环境下是不同的。这里使用的是文本测试环境,所以用的是 junit.textui.testrunner。各个类的职责如下:
1.testresult,负责收集testcase所执行的结果,它将结果分为两类,客户可预测的failure和没有预测的error。同时负责将测试结果转发到testlistener(该接口由testrunner继承)处理;
2.testrunner,客户对象调用的起点,负责对整个测试流程的跟踪。能够显示返回的测试结果,并且报告测试的进度。
3.testsuite, 负责包装和运行所有的testcase。
4.testcase, 客户测试类所要继承的类,负责测试时对客户类进行初始化,以及测试方法调用。
另外还有两个重要的接口:test和testlistener。
1.test, 包含两个方法:run() 和counttestcases(),它是对测试动作特征的提取。
2.testlistener, 包含四个方法:adderror()、addfailure()、starttest()和endtest(),它是对测试结果的处理以及测试驱动过程的动作特征的提取。
下面给出的两个类图(篇幅有限,只显示主要部分)很好地阐明了类之间的关系,以及junit的设计目标(如图1)。测试案例的类采用composite模式。这样,客户的测试对象就转变成一个“部分—整体”的层次结构。客户代码仅需要继承类testcase,就可以轻松的与已有的其他对象组合使用,从而使得单元测试的集成更加方便。
图1 测试结构图
图2是测试跟踪类图。图2左边testsuite包含了测试对象集合,右边包含了测试结果集。具体如何处理结果,以及包含哪些测试对象,并没有立即得出结论,而是尽量地延迟到具体实现的时候。例如,实现接口testlistener的junit中就含有:junit.awtui.testrunner、junit.swingui. testrunner、junit.ui.testrunner等,甚至客户用自己的类实现testlistener,从而达到多样化的目的。
图2 测试跟踪图
从以上两个类图,可以了解junit对单元测试的基本思路,这个框架的核心就是结果集和案例集。
junit的实现流程
典型的使用junit的方法就是继承testcase类,然后重载它的一些重要方法:setup()、teardown()、runtest()(这些都是可选的),最后将这些客户对象组装到一个testsuite对象中,交由 junit.textui.testrunner.run (案例集) 驱动。下面分析案例集是如何运转的。
图3基本上阐述junit的测试流程架构。我们将从不同的角度来详细分析这个图。
图3 测试序列图
首先,从对象的创建上来分析。客户类负责创建suite和atestrunner。注意,类testrunner含有一个静态函数run(test),它自创建本身,然后调用dorun()。客户类调用的一般是该函数,其代码如下:
static public void run(test suite)
{
testrunner atestrunner= new testrunner();//新建测试驱动
atestrunner.dorun(suite, false);//用测试驱动运行测试集
}
suite对象负责创建众多的测试案例,并将它们包容到本身。客户测试案例继承testcase类,它将类,而不是对象传给suite对象。suite对象负责解析这些类、提取构造函数和待测试方法。以待测试方法为单位构造测试案例,测试案例的fname就是待测试方法名。测试结果集由atestrunner创建。这似乎同先前阐述的类图有些矛盾,那里阐述了一个测试集可以包含很多个不同的测试驱动,似乎先创建结果集比较理想。显然,这里对测试结果的处理只采用了一种方式,所以这样做同样可行。
其次,从测试动作的执行上来分析,测试真正是从suite.run(result) 开始的。其代码如下:
public void run(testresult result)
{
//从案例集中获得所有测试案例,分别执行
for (enumeration e= tests(); e.hasmoreelements(); )
{
if (result.shouldstop() )
break;
test test= (test)e.nextelement();
runtest(test, result);
}
}
一旦测试案例开始执行,首先使用一个回调策略将自身交由result。这样做的每一步测试,测试驱动atest runner都可以跟踪处理。这无形中建立了一个庞大的监视系统,随时都可以对所发生的事件给予不同等级的关注。
我们分析一下涉及到的动作行为的设计模式:
1. template method (模板方法)类行为模式,它的实质就是首先建立方法的骨架,而尽可能地将方法的具体实现向后推移。testcase.runbare()就采用了这种模式,客户类均可以重载它的三个方法,这样使得测试的可伸缩性得到提高。
public void runbare() throws throwable
{
setup();
try {runtest();}
finally {teardown();}
}
2. command (命令)对象行为模式,其实质就是将动作封装为一个对象,而不关心动作的接收者。这样动作的接收者可以一直到动作具体执行时才需确定。接口test就是一个command集,使得不同类的不同测试方法可以通过同一种接口test构造其框架结构。这样对测试的集成带来了很多方便。
junit的exception的抛出机制
junit的异常层次分为三层:1.failure,客户预知的测试失败,可以被assert方法检测到;2. error,客户测试的意外造成的;3.systemerror, junit的线程死亡级异常,这种情况一般很少发生。junit的这三种异常在testresult类的runprotected()方法得到很好体现。这里用protectable接口封装了test的执行方法,其实p.protect执行的就是test.runbare()。
public void runprotected(final test test, protectable p)
{
try {p.protect();}
catch (assertionfailederror e)
{addfailure(test, e);}
catch (threaddeath e)
{rethrow e;}
catch (throwable e)
{adderror(test, e);}
}
代码首先检查是否是assertion failederror,然后判断是否是严重的threaddeath。这种异常必须
责任编辑: efish
参与评论
查找更多:
核心java基础j2eexmlj2sej2me问题解决核心技术高级核心java基础j2eexmlj2sej2me问题解决核心技术高级核心java基础j2eexmlj2sej2me问题解决核心技术高级核心java基础j2eexmlj2sej2me问题解决核心技术高级核心java基础j2eexmlj2sej2me问题解决核心技术高级核心java基础j2eexmlj2sej2me问题解决核心技术高级核心java基础j2eexmlj2sej2me问题解决核心技术高级核心java基础j2eexmlj2sej2me问题解决核心技术高级核心java基础j2eexmlj2sej2me问题解决核心技术高级核心java基础j2eexmlj2sej2me问题解决核心技术高级核心java基础j2eexmlj2sej2me问题解决核心技术高级核心java基础j2eexmlj2sej2me问题解决核心技术高级核心java基础j2eexmlj2sej2me问题解决核心技术高级核心java基础j2eexmlj2sej2me问题解决核心技术高级
-
相关文章
tomcat类加载机制
tomcat server在启动的时候将构造一个classloader树,以保证模块的类库是私有的 tomcat server的classlo..
判断java_home友好提示用户
javalauncherbat.zip 4kb
这个脚本执行后判断 java_home 是不是有效, 如果找不到的话就打开帮助页面指..
如何同时启动多个tomcat服务器
前些时日,出于某种需要,需要同时启动多个tomcat服务器,在网上查了半天,才找到解决的办法,拿出来分享一..
tomcat深入??内部结构描述
tomcat服务器是一种servlet/jsp容器,更实质性的说是servlet容器,因为jsp最终还是被编译成servlet来执行的..
开源技术:tomcat5.0下配置ssl
1、使用java1.4版本 2、设置环境变量: path=/usr/j2sdk1.4.1/bin java_home=/usr/j2sdk1.4.1/ classpath=/..
开源技术基础:tomcat的用法
谨以此文送给所有正在使用tomcat或者打算使用的人们,向tomcat的所有开发人员致敬!
一、小猫tomcat其实很可..
2秒记住本站域名
玩过泡泡龙吗?Readygo?Go! 再加上.Com.Cn的后缀,那就是大名小顶的ReadyGo.com.cn
