JUnit讲课文档.docx
- 文档编号:8496493
- 上传时间:2023-01-31
- 格式:DOCX
- 页数:30
- 大小:971.72KB
JUnit讲课文档.docx
《JUnit讲课文档.docx》由会员分享,可在线阅读,更多相关《JUnit讲课文档.docx(30页珍藏版)》请在冰豆网上搜索。
JUnit讲课文档
在Eclipse中使用JUnit
测试对于保证软件开发质量有着非常重要的作用,单元测试更是必不可少,JUnit是一个非常强大的单元测试包,可以对一个/多个类的单个/多个方法测试,还可以将不同的TestCase组合成TestSuit,使测试任务自动化。
Eclipse同样集成了JUnit,可以非常方便地编写TestCase。
我们创建一个Java工程,添加一个example.Hello类,首先我们给Hello类添加一个abs()方法,作用是返回绝对值:
下一步,我们准备对这个方法进行测试,确保功能正常。
选中Hello.java,右键点击,选择New->JUnitTestCase:
Eclipse会询问是否添加junit.jar包,确定后新建一个HelloTest类,用来测试Hello类。
FenGFly.COM网页特效—雨枫技术教程网雨枫技术教程网雨枫技术FengFLY,com
选中setUp()和tearDown(),然后点击“Next”:
选择要测试的方法,我们选中abs(int)方法,完成后在HelloTest.java中输入:
JUnit会以以下顺序执行测试:
(大致的代码)
try{
HelloTesttest=newHelloTest();//建立测试类实例
test.setUp();//初始化测试环境
test.testAbs();//测试某个方法
test.tearDown();//清理资源
}
catch…
setUp()是建立测试环境,这里创建一个Hello类的实例;tearDown()用于清理资源,如释放打开的文件等等。
以test开头的方法被认为是测试方法,JUnit会依次执行testXxx()方法。
在testAbs()方法中,我们对abs()的测试分别选择正数,负数和0,如果方法返回值与期待结果相同,则assertEquals不会产生异常。
如果有多个testXxx方法,JUnit会创建多个XxxTest实例,每次运行一个testXxx方法,setUp()和tearDown()会在testXxx前后被调用,因此,不要在一个testA()中依赖testB()。
专业技术教程
专业技术教程www.FengfLy.CoM
直接运行Run->RunAs->JUnitTest,就可以看到JUnit测试结果。
绿色表示测试通过,只要有1个测试未通过,就会显示红色并列出未通过测试的方法。
可以试图改变abs()的代码,故意返回错误的结果(比如returnn+1;),然后再运行JUnit就会报告错误。
如果没有JUnit面板,选择Window->ShowView->Other,打开JUnit的View:
JUnit通过单元测试,能在开发阶段就找出许多Bug,并且,多个TestCase可以组合成TestSuite,让整个测试自动完成,尤其适合于XP方法。
每增加一个小的新功能或者对代码进行了小的修改,就立刻运行一遍TestSuite,确保新增和修改的代码不会破坏原有的功能,大大增强软件的可维护性,避免代码逐渐“腐烂”。
JUnit4测试驱动开发
1预备知识
1.1可变长参数
1.2Assert
1.3Annotation
21.简介
JUnit是Java语言事实上的标准单元测试库。
JUnit的易用性无疑是它受欢迎的主要原因。
也许你会这样想:
它做的事情不多,仅仅是做一些测试然后报告结果,JUnit应该是很简单的。
XP--敏捷编程--领袖
JUnit4.x是最初由ErichGamma和KentBeck编写的,能够自动化测试Java代码的框架,JUnit的一大主要特点是,它在执行的时候,各个方法之间是相互独立的,一个方法的失败不会导致别的方法失败,方法之间也不存在相互依赖的关系,彼此是独立的。
JUnit4是该库以来最具里程碑意义的一次发布。
它的新特性主要是通过采用Java5中的标记(Annotation)而不是利用子类、反射或命名机制来识别测试,从而简化测试。
然而,JUnit仅仅是一个工具而已。
真正的优势来自于JUnit所采用的思想和技术,而不是框架本身。
单元测试、测试先行的编程和测试驱动的开发并非都要在JUnit中实现。
JUnit本身的最后一次更新差不多是三年以前了。
尽管它被证明比大多数框架更健壮、更持久,但是也发现了bug;而更重要的是,Java不断在发展。
Java语言现在支持泛型(RawType)、枚举(Enum)、可变长度参数列表和注释,这些特性为可重用的框架设计带来了新的可能。
新版本的JUnit,它利用Java5的新特性(尤其是注释)的优势,使得单元测试比起用最初的JUnit来说更加简单。
用Beck的话来说,“JUnit4的主题是通过进一步简化JUnit,鼓励更多的开发人员编写更多的测试。
”JUnit4尽管保持了与现有JUnit3.8测试套件的向后兼容,但是它仍然承诺是自JUnit1.0以来Java单元测试方面最重大的改进。
2.1一个最简单的测试
2.1.13.8系列
以前所有版本的JUnit都使用命名约定和反射来定位测试。
例如,下面的代码测试1+1等于2:
importjunit.framework.TestCase;
publicclassAdditionTestextendsTestCase{
privateintx=1;
privateinty=1;
publicvoidtestAddition(){
intz=x+y;
assertEquals(2,z);
}
}
2.1.24.X系列
在JUnit4中,测试是由@Test注释来识别的,如下所示:
importorg.junit.Test;
importjunit.framework.TestCase;
publicclassAdditionTestextendsTestCase{
privateintx=1;
privateinty=1;
@TestpublicvoidtestAddition(){
intz=x+y;
assertEquals(2,z);
}
}
使用注释的优点是不再需要将所有的方法命名为testFoo()、testBar(),等等。
而在3.8中如果你的方法不是以test开头的,将不被解释为测试方法。
这允许您遵循最适合您的应用程序的命名约定。
通过继承TestCase类的方式,仍然可以工作,但是您不再需要扩展它了。
只要您用@Test来注释测试方法,就可以将测试方法放到任何类中。
但是您需要导入junit.Assert类以访问各种assert方法,如下所示:
importorg.junit.Assert;
publicclassAdditionTest{
privateintx=1;
privateinty=1;
@Testpublicvoidaddition(){
intz=x+y;
Assert.assertEquals(2,z);
}
}
还可以使用JDK5中新特性(staticimport),使得与以前版本一样简单:
importstaticorg.junit.Assert.assertEquals;
publicclassAdditionTest{
privateintx=1;
privateinty=1;
@Testpublicvoidaddition(){
intz=x+y;
assertEquals(2,z);
}
}
这种方法使得测试受保护的方法非常容易,因为测试案例类现在可以扩展包含受保护方法的类了。
2.2什么是单元测试
单元测试是由程序员编写的,测试被测试代码的某一个很小的、特定的功能区域的代码。
它可以用来确保在代码或者程序运行的环境中发生变化后,已经存在的功能还是能够执行的。
2.3在Eclipse中使用JUnit
准备
创建一个新的工程,并增加JUnit到库到项目的BuildPath中。
创建一个普通类
创建名字为"MyClass"的Java文件
牋牋牋牋牋牋
publicclassMyClass{
牋爌ublicintmultiply(intx,inty){
牋牋牋returnx/y;
牋爙
}
创建测试类
创建测试套件
如果你有很多个测试,想要合并到一起来执行,你可以创建一个TestSuite.在一个TestSuite中的所有的测试将会被执行。
3SetUp和TearDown及断言方法
3.13.8系列
JUnit3测试运行程序(testrunner)会在运行每个测试之前自动调用setUp()方法。
该方法一般会初始化字段,打开日志记录,重置环境变量,等等。
例如,下面是摘自XOM的XSLTransformTest中的setUp()方法:
protectedvoidsetUp(){
System.setErr(newPrintStream(newByteArrayOutputStream()));
inputDir=newFile("data");
inputDir=newFile(inputDir,"xslt");
inputDir=newFile(inputDir,"input");
}
在JUnit3中,您使用tearDown()方法,该方法类似于我在XOM中为消耗大量内存的测试所使用的方法:
protectedvoidtearDown(){
doc=null;
System.gc();
}
3.24.X系列
在JUnit4中,您仍然可以在每个测试方法运行之前初始化字段和配置环境。
然而,完成这些操作的方法不再需要叫做setUp(),只要用@Before注释来指示即可,如下所示:
@Beforeprotectedvoidinitialize(){
System.setErr(newPrintStream(newByteArrayOutputStream()));
inputDir=newFile("data");
inputDir=newFile(inputDir,"xslt");
inputDir=newFile(inputDir,"input");
}
甚至可以用@Before来注释多个方法,这些方法都在每个测试之前运行:
@BeforeprotectedvoidfindTestDataDirectory(){
inputDir=newFile("data");
inputDir=newFile(inputDir,"xslt");
inputDir=newFile(inputDir,"input");
}
@BeforeprotectedvoidredirectStderr(){
System.setErr(newPrintStream(newByteArrayOutputStream()));
}
对于JUnit4,我可以给它取一个更自然的名称,并用@After注释它:
@AfterprotectedvoiddisposeDocument(){
doc=null;
System.gc();
}
与@Before一样,也可以用@After来注释多个清除方法,这些方法都在每个测试之后运行。
最后,您不再需要在超类中显式调用初始化和清除方法,只要它们不被覆盖即可,测试运行程序将根据需要自动为您调用这些方法。
超类中的@Before方法在子类中的@Before方法之前被调用(这反映了构造函数调用的顺序)。
@After方法以反方向运行:
子类中的方法在超类中的方法之前被调用。
否则,多个@Before或@After方法的相对顺序就得不到保证。
3.3断言方法
3.8系列,每一个类都继承了一个叫做TestCase的类,而TestCase的父类是Assert类
4.x系列,每一个可以不继承任何的类
,但是仍然可以直接使用
importstaticorg.junit.Assert.*;
在3.8当中,所有的测试类必须都是TestCase的子类
4.X中,测试类可以是一个普通类,也可以去继承一个类或者实现一个接口
要实现测试,只需要在要测试的方法之前加@Test注释
same---相同
equal---相等
4注释(Annotations)
Annotation
含义
@Testpublicvoidmethod()
定义一个要测试的方法
@Beforepublicvoidmethod()
在每一个测试之前都会被执行的方法,这个方法常常用来进行一
些测试环境的准备,比喻说读入输入数据,初始化类
@Afterpublicvoidmethod()
与@Before进行对应,做一个清理工作
@BeforeClasspublicvoidmethod()
在所有的测试开始之前执行,这个方法在类运行的时候运行,
而且只会运行一次,所以常常用来做一些所有的方法都要依赖
到工作,比喻说,数据库的链接。
@AfterClasspublicvoidmethod()
与@BeforeClass进行对应,做一些类级别的清理工作
@Ignore
表明方法是被忽略的,这个方法非常实用,比喻你的方法已经
修改,但是对应的测试方法还没有得到一致的修改的时候,可以
忽略掉这个测试方法先。
@Test(expected=IllegalArgumentException.class)
检查测试方法是不是抛出了对应的异常
@Test(timeout=100)
如果方法的执行操作所耗费的毫秒数>100MS,那么方法失败。
表格1Annotations
5新的断言
JUnit4为比较数组添加了两个assert()方法:
publicstaticvoidassertEquals(Object[]expected,Object[]actual)
publicstaticvoidassertEquals(Stringmessage,Object[]expected,
Object[]actual)
这两个方法以最直接的方式比较数组:
如果数组长度相同,且每个对应的元素相同,则两个数组相等,否则不相等。
数组为空的情况也作了考虑。
6套件范围的初始化
JUnit4也引入了一个JUnit3中没有的新特性:
类范围的setUp()和tearDown()方法。
任何用@BeforeClass注释的方法都将在该类中的测试方法运行之前刚好运行一次,而任何用@AfterClass注释的方法都将在该类中的所有测试都运行之后刚好运行一次。
例如,假设类中的每个测试都使用一个数据库连接、一个网络连接、一个非常大的数据结构,或者还有一些对于初始化和事情安排来说比较昂贵的其他资源。
不要在每个测试之前都重新创建它,您可以创建它一次,并还原它一次。
该方法将使得有些测试案例运行起来快得多。
例如,当我测试调用第三方库的代码中的错误处理时,我通常喜欢在测试开始之前重定向System.err,以便输出不被预期的错误消息打乱。
然后我在测试结束后还原它,如下所示:
//Thisclasstestsalotoferrorconditions,which
//XalanannoyinglylogstoSystem.err.ThishidesSystem.err
//beforeeachtestandrestoresitaftereachtest.
privatePrintStreamsystemErr;
@BeforeClassprotectedvoidredirectStderr(){
systemErr=System.err;//Holdontotheoriginalvalue
System.setErr(newPrintStream(newByteArrayOutputStream()));
}
@AfterClassprotectedvoidtearDown(){
//restoretheoriginalvalue
System.setErr(systemErr);
}
没有必要在每个测试之前和之后都这样做。
但是一定要小心对待这个特性。
它有可能会违反测试的独立性,并引入非预期的混乱。
如果一个测试在某种程度上改变了@BeforeClass所初始化的一个对象,那么它有可能会影响其他测试的结果。
它有可能在测试套件中引入顺序依赖,并隐藏bug。
与任何优化一样,只在剖析和基准测试证明您具有实际的问题之后才实现这一点。
这就是说,我看到了不止一个测试套件运行时间如此之长,以至不能像它所需要的那样经常运行,尤其是那些需要建立很多网络和数据库连接的测试。
(例如,LimeWire测试套件运行时间超过两小时。
)要加快这些测试套件,以便程序员可以更加经常地运行它们,您可以做的就是减少bug。
7测试异常
异常测试是JUnit4中的最大改进。
旧式的异常测试是在抛出异常的代码中放入try块,然后在try块的末尾加入一个fail()语句。
例如,该方法测试被零除抛出一个ArithmeticException:
publicvoidtestDivisionByZero(){
try{
intn=2/0;
fail("Dividedbyzero!
");
}
catch(ArithmeticExceptionsuccess){
assertNotNull(success.getMessage());
}
}
该方法不仅难看,而且试图挑战代码覆盖工具,因为不管测试是通过还是失败,总有一些代码不被执行。
在JUnit4中,您现在可以编写抛出异常的代码,并使用注释来声明该异常是预期的:
@Test(expected=ArithmeticException.class)
publicvoiddivideByZero(){
intn=2/0;
}
如果该异常没有抛出(或者抛出了一个不同的异常),那么测试就将失败。
但是如果您想要测试异常的详细消息或其他属性,则仍然需要使用旧式的try-catch样式。
8可以忽略到测试
也许您有一个测试运行的时间非常地长。
不是说这个测试应该运行得更快,而是说它所做的工作从根本上比较复杂或缓慢。
需要访问远程网络服务器的测试通常都属于这一类。
如果您不在做可能会中断该类测试的事情,那么您可能想要跳过运行时间长的测试方法,以缩短编译-测试-调试周期。
或者也许是一个因为超出您的控制范围的原因而失败的测试。
例如,W3CXInclude测试套件测试Java还不支持的一些Unicode编码的自动识别。
不必老是被迫盯住那些红色波浪线,这类测试可以被注释为@Ignore,如下所示:
//Javadoesn'tyetsupport
//theUTF-32BEandUTF32LEencodings
@IgnorepublicvoidtestUTF32BE()
throwsParsingException,IOException,XIncludeException{
Fileinput=newFile("data/xinclude/input/UTF32BE.xml");
Documentdoc=builder.build(input);
Documentresult=XIncluder.resolve(doc);
DocumentexpectedResult=builder.build(newFile(outputDir,"UTF32BE.xml"));
assertEquals(expectedResult,result);
}
测试运行程序将不运行这些测试,但是它会指出这些测试被跳过了。
但是一定要小心。
最初编写这些测试可能有一定的原因。
如果永远忽略这些测试,那么它们期望测试的代码可能会中断,并且这样的中断可能不能被检测到。
忽略测试只是一个权宜之计,不是任何问题的真正解决方案。
9时间测试
10Failure和Error
Failure指的是由于预期的结果与实际运行的测试的结果不同而导致的實際運行單元的結果不同所導致,例如当使用assertEquals()或其它assertXXX()方法断言失败时,就会报出Failure,如果发现Faulure,你就要去检查你的测试方法或者是被测试方法中编写的逻辑是否有误。
Error指的是编写程序时没有考虑到的问题。
在执行测试的断言之前,程序就因为某种类型的意外而停止,比喻说我们在操作数组的时候,因为存取超出索引会引发ArrayIndexOutOfBoundsException,这个时候程序就会报出Error,程序将无法运行下去,提前结束,这个时候你要检查被测试方法中是不是有欠缺考虑到地方。
看一个具体的例子:
importjunit.framework.TestCase;
publicclassObjectArrayTestextendsTestCase{
牋_publicvoidtestAdd(){
牋牋牋_ObjectArrayobjArr=newObjectArray();
牋牋牋_ObjecttestObj=newObject();
牋牋牋_Objectobj=objArr.setObject(0,testObj);
牋牋牋_assertEquals(testObj,obj);
牋_}
}
如果执行这个测试的话,Eclipse会提示你创建一个名字为ObjectArray的类,在其中要求你创建一个名字为setObject的方法。
假设你创建的类的样子如下:
publicclassObjectArray{
牋publicObjectsetObject(inti,ObjecttestObj){
牋爎eturnnull;
牋}
}
如果现在你来运行测试的话,会出现以下类似的界面:
大家注意看,里面报出了Failures:
1
为什么呢?
_Objectobj=objArr.setObject(0,testObj);
牋assertEquals(
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- JUnit 讲课 文档