junit工具及使用Word文件下载.docx
- 文档编号:21509875
- 上传时间:2023-01-30
- 格式:DOCX
- 页数:63
- 大小:1.97MB
junit工具及使用Word文件下载.docx
《junit工具及使用Word文件下载.docx》由会员分享,可在线阅读,更多相关《junit工具及使用Word文件下载.docx(63页珍藏版)》请在冰豆网上搜索。
选中Hello.java,右键点击,选择New->
other在弹出的对话框中选择java->
JUnit->
JUnitTestCase点击Next按钮,弹出如图6-2对话框:
图6-2建立TestCase
默认选项,点击Next按钮,进入图6-3,选择要进行测试的方法,把Hello类的reAbs方法勾选上,点击Finish按钮,系统自动生成对Hello类的测试类HelloTest,源代码如下:
图6-3建立Test方法
importstaticorg.junit.Assert.*;
importorg.junit.After;
importorg.junit.Before;
importorg.junit.Test;
publicclassHelloTest{
@Before//JavaAnotation注释性编程,
publicvoidsetUp()throwsException{
@After
publicvoidtearDown()throwsException{
@Test
publicvoidtestReAbs(){
fail("
Notyetimplemented"
);
修改如下:
privateHellohello;
@Before
hello=newHello();
inta1=hello.reAbs(20);
assertEquals(20,a1);
//――――――#1
然后运行HelloTest类查看运行结果,如下图所示:
图6-4Errors=0,Failures=0,绿色条代表测试通过。
将1处代码修改如下:
assertEquals(-20,a1);
再次运行HelloTest类查看运行结果,如下图所示:
图6-5Errors=0,Failures=1,红条代表有测试方法没有通过。
在HelloTest类中,@Before注释的方法是建立测试环境,这里创建一个Hello类的实例;
@After注释的方法用于清理资源,如释放打开的文件等等。
以@Test注释的方法被认为是测试方法,JUnit会依次执行这些方法。
在testReAbs()方法中,我们对reAbs()的测试分别2次测试,assertEquals方法比较运行结果和预期结果是否相同。
如果有多个测试方法,JUnit会创建多个测试实例,每次运行一个测试方法,@Before和@After注释的方法会在测试实例前后被调用,因此,不要在一个testA()中依赖testB()。
现在我们在Hello类中增加一个方法,代码如下:
publicdoubleadd(doublenumber1,doublenumber2){
returnnumber1+number2;
然后在HelloTest类中增加一个测试方法TestAdd,代码如下:
@Test
publicvoidtestAdd(){
doubleresult=hello.add(10,30);
assertEquals(40,result,0);
运行HelloTest类查看运行结果。
AssertEquals方法中的第三个参数表示的是允许误差范围。
6.2Junit框架分析
自动化测试框架就是可以自动对代码进行单元测试的框架。
在传统的软件开发流程中,需求,设计,编码和测试都有各自独立的阶段,阶段之间不可以回溯,所以测试是不是自动化并不重要。
新的软件开发流程中,引入了迭代开发的概念,并且项目迭代周期短,对代码要进行频繁的重构,这就要求单元级测试必须能够自动、简便、高速的运行,否则重构就是不现实的。
自动化测试框架应该支持简单操作,向测试包中添加新的测试用例,而且不影响测试包的正常运行。
Junit的自动化测试框架图如下:
图3-6Junit自动化测试框架
这是一个典型的Composite设计模式:
TestSuite可以容纳任何派生自Test的对象;
当调用TestsSuite对象的run()方法时,它会遍历自己容纳的对象,逐个调用它们的run()方法。
使用者无须关心自己拿到的究竟是TestCase还是TestSute,只管调用对象的run()方法,然后分析run()方法返回的结果就行了
●TestCase(测试用例)——扩展了JUnit的TestCase类的类。
它以testXXX方法的形式包含一个或多个测试。
一个testcase把具有公共行为的测试归入一组。
在本书的后续部分,当我们提到测试的时候,我们指的是一个testXXX方法;
当我们提及testcase的时候,我们指的是一个继承自TestCase的类,也就是一组测试。
●TestSuite(测试集合)——一组测试。
一个testsuite是把多个相关测试归入一组的便捷方式。
例如,如果你没有为TestCase定义一个testsuite,那么JUnit就会自动提供一个testsuite,包含TestCase中所有的测试(本书稍后会细说)。
●TestRunner(测试运行器)——执行testsuite的程序。
JUnit提供了几个testrunner,你可以用它们来执行你的测试。
没有TestRunner接口,只有一个所有testrunner都继承的BaseTestRunner。
因此,当我们编写TestRunner的时候,我们实际上指的是任何继承BaseTestRunner的testrunner类。
图3-7
JUnit成员三重唱,共同产生测试结果
这3个类是JUnit框架的骨干。
一旦你理解了TestCase、TestSuite和BaseTestRunner的工作方式,你就可以随心所欲地编写测试了。
在正常情况下,你只需要编写testcase,其他类会在幕后帮你完成测试。
这3个类和另外4个类紧密配合,形成了JUnit框架的核心。
图3-8归纳了这7个核心类各自的责任。
图3-8Junit核心类及接口
6.3用TestCase来工作
概括地说,JUnit的工作过程就是由TestRunner来运行包含一个或多个TestCase(或者其他TestSuite)的TestSuite。
但在常规工作中,你通常只和TestCase打交道。
有些测试会用到一些资源,要把这些资源配置好是件麻烦事。
比如像数据库连接这样的资源就是典型的例子。
可能TestCase中的几个测试需要连接到一个测试数据库并访问一些测试表。
另一组测试则可能需要复杂的数据结构或者很长的随机输入序列。
把通用的资源配置代码放在测试中并不是好主意。
你并不想测试自己建立资源的能力,你只需要一个稳健的外部环境,在这个环境中运行测试。
运行测试所需要的这个外部资源环境通常称作testfixture。
定义
fixture——运行一个或多个测试所需的公用资源或数据集合。
TestCase通过setUp和tearDown方法来自动创建和销毁fixture。
TestCase会在运行每个测试之前调用setUp,并且在每个测试完成之后调用tearDown。
把不止一个测试方法放进同一个TestCase的一个重要理由就是可以共享fixture代码。
图3-9描述了TestCase的生命周期。
需要fixture的一个典型例子就是数据库连接。
如果一个TestCase包括好几项数据库测试,那么它们都需要一个新建立的数据库连接。
通过fixture就可以很容易地为每个测试开启一个新连接,而不必重复编写代码。
你还可以用fixture来生成输入文件,这意味着你不必在测试中携带测试文件,而且在测试开始执行之前状态总是已知的。
JUnit还通过Assert接口提供的工具方法来复用代码。
我们将在下一节中加以介绍。
图3-9TestCase生命周期,为每个测试方法重新创建fixture
在测试一个单元方法时,有时您会需要给它一些对象作为运行时的资料,例如您撰写下面这个测试案例:
∙MaxMinTest.java
packageonlyfun.caterpillar.test;
importonlyfun.caterpillar.MaxMinTool;
importjunit.framework.TestCase;
publicclassMaxMinTestextendsTestCase{
publicvoidtestMax(){
int[]arr={-5,-4,-3,-2,-1,0,1,2,3,4,5};
assertEquals(5,MaxMinTool.getMax(arr));
publicvoidtestMin(){
assertEquals(-5,MaxMinTool.getMin(arr));
}
您将设计的MaxMinTool包括静态方法getMax()与getMin(),当您给它一个整数阵列,它们将个别传回阵列中的最大值与最小值,显然的,您所准备的阵列重复出现在两个单元测试之中,重复的程式码在设计中可以减少就尽量减少,在这两个单元测试中,整数阵列的准备是单元方法所需要的资源,我们称之为fixture,也就是一个测试时所需要的资源集合。
fixture必须与上下文(Context)无关,也就是与程式执行前后无关,这样才符合单元测试的意涵,为此,通常将所需的fixture撰写在单元方法之中,如此在单元测试开始时创建fixture,并于结束后销毁fixture。
然而对于重复出现在各个单元测试中的fixture,您可以集中加以管理,您可以在继承TestCase之后,重新定义setUp()与tearDown()方法,将数个单元测试所需要的fixture在setUp()中创建,并在tearDown()中销毁,例如:
MaxMinTest.java
privateint[]arr;
protectedvoidsetUp()throwsException{
super.setUp();
arr=newint[]{-5,-4,-3,-2,-1,0,1,2,3,4,5};
protectedvoidtearDown()throwsException{
super.tearDown();
arr=null;
setUp()方法会在每一个单元测试testXXX()方法开始前被呼叫,因而整数阵列会被建立,而tearDown()会在每一个单元测试testXXX()方法结束后被呼叫,因而整数阵列参考名称将会参考至null,如此一来,您可以将fixture的管理集中在setUp()与tearDown()方法之后。
最后按照测试案例的内容,您完成MaxMinTool类别:
∙
MaxMinTool.java
packageonlyfun.caterpillar;
publicclassMaxMinTool{
publicstaticintgetMax(int[]arr){
intmax=Integer.MIN_VALUE;
for(inti=0;
i<
arr.length;
i++){
if(arr[i]>
max)
max=arr[i];
returnmax;
publicstaticintgetMin(int[]arr){
intmin=Integer.MAX_VALUE;
if(arr[i]<
min)
min=arr[i];
returnmin;
Swing介面的TestRunner在测试失败时会显示红色的棒子,而在测试成功后会显示绿色的棒子,而"
Keepthebargreentokeepthecodeclean."
正是JUnit的名言,也是测试的最终目的。
6.4
创建单元测试方法
使用fixture是复用配置代码的好办法。
但是还有很多常见的任务,很多测试都会重复执行这些任务。
JUnit框架用一组assert方法封装了最常见的测试任务。
这些assert方法可以极大地简化单元测试的编写。
Assert超类型
Assert类包含了一组静态的测试方法,用于验证期望值expected和实际值actual逻辑比对是否正确,即测试失败,标志为未通过测试。
如果期望值和实际值比对失败,Assert类就会抛出一个AssertionFailedError异常,Junit测试框架将这种错误归入Fails并且加以记录。
每一个Assert类所属的方法都会被重载(OverLoaded),如果指定了一个String类型的传参则该参数将被做为AssertionFailedError异常的标识信息,告诉测试人员该异常的具体信息。
定义assert方法的辅助类的名称:
Assert类。
这个类包含了很多对于编写测试很有用的具体代码。
Assert只有8个公有核心公有核心方法(如下图所示)。
图3-10
Assert超类所提供的8个核心方法
Javadoc中充满了这8个方法的便捷形式。
这些便捷形式使得传递在测试中需要的任何类型都很简单。
以assertEquals方法为例,它就有20种形式!
大多数形式都是便捷形式,最终还是调用了核心的assertEquals(Stringmessage,Objectexpected,Objectactual)方法。
保持测试的独立性
在你开始编写自己的测试的时候,请记住第一条规则:
每项单元测试都必须独立于其他所有单元测试而运行。
单元测试必须能以任何顺序运行,一项测试不能依赖于前面的测试造成的改变(比如把某个成员变量设置成某个状态)。
如果一项测试依赖于其他测试,那么你是在自找麻烦。
下面是相互依赖的测试会造成的问题:
不具可移植性——默认情况下,JUnit通过反射来测试方法。
反射API并不保证返回方法名的顺序。
如果你的测试依赖于这个顺序,那么可能你的testsuite在某个JVM上运行正常,但在另一个JVM上无法运行。
难以维护——当你修改一项测试,你会发现其他一批测试也受到了影响。
若你需要修改其它测试,那么你在花时间维护测试,而这些时间本可用于开发代码。
不够清晰——为了理解相互依赖的测试是如何工作的,你必须理解每个测试是如何工作的,这样测试就变得难读也难以掌握。
好的测试必须简单易懂、易于掌握。
6.5TestSuite
您定义自己的TestCase,并使用TestRunner来运行测试,事实上TestRunner并不直接运行TestCase上的单元方法,而是透过TestSuite,TestSuite可以将数个TestCase在一起,而让每个TestCase保持简单。
来看看一个例子:
MathToolTest.java
importonlyfun.caterpillar.MathTool;
publicclassMathToolTestextendsTestCase{
publicMathToolTest(StringtestMethod){
super(testMethod);
publicvoidtestGcd(){
assertEquals(5,MathTool.gcd(10,5));
publicstaticvoidmain(String[]args){
junit.textui.TestRunner.run(MathToolTest.class);
在这个例子中,您并没有看到任何的TestSuite,事实上,如果您没有提供任何的TestSuite,TestRunner会自己建立一个,然后这个TestSuite会使用反射(reflection)自动找出testXXX()方法。
如果您要自行生成TestSuite,则在继承TestCase之后,提供静态的(static)的suite()方法,例如:
publicstaticTestsuite(){
returnnewTestSuite(MathTool.class);
如果您没有提供任何的TestSuite,则TestRunner就会像上面这样自动为您建立一个,并找出testXXX()方法,您也可以如下面定义suite()方法:
TestSuitesuite=newTestSuite(MathTool.class);
suite.addTest(newMathToolTest("
testGcd"
));
returnsuite;
JUnit并没有规定您一定要使用testXXX()这样的方式来命名您的测试方法,如果您要提供自己的方法(当然JUnit鼓励您使用testXXX()这样的方法名称),则可以如上撰写,为了要能够使用建构函式提供测试方法名称,您的TestCase必须提供如下的建构函式:
publicMathToolTest(StringtestMethod){
如果要加入更多的测试方法,使用addTest()就可以了,suite()方法传回一个TestSuite物件,它与TestCase都实作了Test介面,TestRunner会调用TestSuite上的run()方法,然后TestSuite会将之委托给TestCase上的run()方法,并执行每一个testXXX()方法。
除了组合TestCase之外,您还可以将数个TestSuite组合在一起,例如:
publicstaticTestsuite(){
TestSuitesuite=newTestSuite();
suite.addTestSuite(TestCase1.class);
suite.addTestSuite(TestCase2.class);
如此之来,您可以一次运行所有的测试,而不必个别的运行每一个测试案例,您可以写一个运行全部测试的主测试,而在使用TestRunner时呼叫suite()方法,例如:
junit.textui.TestRunner.run(TestAll.suite());
TestCase与TestSuite都实现了Test介面,其运行方式为Command模式的一个实例,而TestSuite可以组合数个TestSuite或TestCase,这是Composite模式的一个实例。
6.6FailError
在运行TestRunner执行您的测试时,您会发现到有Failure与Error两种测试尚未通过的讯息。
Failure指的是预期的结果与实际运行单元的结果不同所导致,例如当您使用assertEquals()或其它assertXXX()方法断言失败时,就会回报Failure,这时候您要检查您的单元方法中的逻辑设计是否有误。
Error指的是您程式没有考虑到的情况,在断言之前程式就因为某种错误引发例外而终止,例如在单元中存取某个阵列,因为存取超出索引而引发ArrayIndexOutOfBoundsException,这会使得单元方法无法正确完成,在测试运行到asertXXXX()前就提前结束,这时候您要检查您的单元方法中是否有未考虑到的情况而引发流程突然中断。
来看个实际的例子,如果您设计了下面的测试案例:
ObjectArrayTest.java
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- junit 工具 使用