JBuilder0520单元测试体验.docx
- 文档编号:6470132
- 上传时间:2023-01-06
- 格式:DOCX
- 页数:40
- 大小:750.28KB
JBuilder0520单元测试体验.docx
《JBuilder0520单元测试体验.docx》由会员分享,可在线阅读,更多相关《JBuilder0520单元测试体验.docx(40页珍藏版)》请在冰豆网上搜索。
JBuilder0520单元测试体验
JBuilder2005单元测试体验
白盒测试是软件工程中重要的概念,开发人员往往要花1/3时间测试自己编写的程序。
一个类所有开放的API接口都必须通过白盒测试,JBuilder集成了目前流行的JUnit单元测试框架,提供了创建、运行、编译测试用例的支持。
自动测试代码的重要性
一个产品只有通过检验才能投放市场,同样的,一个业务类也只有在经验测试后才能保证功能的正确性,以便被其他类或程序调用,否则隐藏其中的Bug就蔓延开了。
业务功能点测试是测试人员的职责,但业务类API的正确性必须由开发人员保证。
一个产品只有通过检验才能投放市场,同样的,一个业务类也只有在经验测试后才能保证功能的正确性,以便被其他类或程序调用,否则隐藏其中的Bug就蔓延开了。
业务功能点测试是测试人员的职责,但业务类API的正确性必须由开发人员保证。
回忆一下最近你所开发的系统,往往一个最难忘的情节是通宵达旦地毯式搜索某个刁专的Bug,历尽千辛万苦,最终找到并解决了它。
查找一个隐藏的Bug往往是踏破铁蹄无觅处,而找到后却是:
解决全不费功夫。
造成这尴尬窘局有以下几点原因:
其一是使用增量式测试策略,即先编写功能代码,在模块开发完毕后才回过头来编写测试用例,因为一个功能模块可能包含许多相互关联的类,形成了层层调用,交错复杂的调用网络,一旦发现了Bug,只得查户口似的逐一排查,其艰辛程度可想而知。
其二是使用不正确的测试方法,如在每个类中提供一个main()测试函数,对类中的功能方法进行测试,通过运行类的main()方法查看类功能的正确性。
在某种程序上,这或许是一个值得赞扬的工作习惯,但工作方式却不足取。
因为每个类都必须单独运行,以执行其测试功能,并由开发人员观察测试的正确性。
随着程序规模的扩大,类数目直线上升,原有的类也会发生代码的调整,一些功能点可能就变成了漏网之鱼,变成了茫茫"类"海里的黑户口,将来"违法乱纪"起来就很难监控了。
针对这些传统测试思想的不足,测试先行、频繁测试、自动测试的测试思想被越来越多的开发人员所接受并付诸实践。
测试先行乍听起来有点让人不可思议,一件东西还没有做出来就想着怎么去测试它?
仔细分析,这并不荒唐,因为这让你在设计类时,站在调用者的角度去理解类的对外接口,迫使你深入理解类的外在关系,考虑接口的用途,而在具体编写程序时才去具体考虑内部实现细节,这样设计出接口将更易使用,结构也会更趋合理。
频繁测试,即指测试不应当是阶段性的工作,而应当在程序编写过程中不断进行。
因为系统中的类之间往往都存在较多的关联关系,当更改了类的功能时,往往会有多个类受到直接或间接的影响。
所以你应该频繁测试以及早发现这种因功能、调整而引起的Bug,越早发现错误解决它的代价越小。
频繁测试也是XP编程的一个重要环节,XP编程总让人觉得他们注重功能实现而忽视测试,其实他们也非常关注测试,毕竟测试可以使他们尽可能快的稳步前进。
所谓自动测试并不是说有一个工具可以让你像安检器一样,自动测试出你类中的问题。
而是指应用一定的测试框架,为每个业务类编写独立的测试用例,类代码调整后,对应的测试用例同步调整。
多个测试用例组成一个测试套件一起批量运行,它们就像一个强大的Bug嗅探器,一旦发现Bug就会输出特定的信息报告错误,只要一个测试用例没有通过测试就说明程序中有问题。
测试用例中所包含的测试规则完成由你定制,这个测试套件对Bug嗅探的"灵敏度"完全取决于测试用例的测试规则,框架提供编写和运行测试用例的规范性方法。
在编写一个业务类时,需要相应编写对应的测试用例,一开始挺招"惯性定律"抵触的,因为它要求你将创建一个测试用例类,似乎需要更多的工作。
但你的付出是会得到加倍回报的,随着软件类规模的增大你会发现,当传统测试方法越来越捉襟见肘,穷于应付时,基于测试框架的测试技术依然"谈笑自如"。
当然别人这么说,我们也不应当马上就深信不疑,疑惑永远是值得推崇的科学精神,我们应该通过自己的实践却真真切切地体会这种改进所带来的快乐。
JUnit测试框架
JUnit是由ErichGamma和KentBeck开发的开源测试框架,JBuilder集成了这个框架并做了扩展。
JUnit之所以流行并为广大的开发人员所推崇,一是它实战性强,功能强大,二是它实在简单。
一个产品或框架要能有生命力,最好都具备这样的特点。
简单的框架
JUnit是由ErichGamma和KentBeck开发的开源测试框架,JBuilder集成了这个框架并对此做了扩展。
JUnit之所以流行并为广大的开发人员所推崇,一是因为它实战性强,功能强大,二是因为它实在简单。
一个产品或框架要能有生命力,最好都具备这样的特点。
简单地讲这个框架提供了许多断言(assert)方法,允许你设置测试的规则,如:
assertEquals()、assertNull()、assertNotSame()、assertTrue()等方法,一个测试用例包括了多个断言,当运行测试用例后,JUnit运行器会报告哪些断言没有通过,开发人员就可顺藤摸瓜搞个水落石出了。
而传统的测试方法需要将期望的结果用诸如System.out.println()等语句将过程信息打印到控制台或日志中,由开发人员观察输出信息以判断是否正确,现在这种"观察"的工作由JUnit的那些assertXxx()方法自动完成。
JUnit的测试框架类结构很简单,主要由3个类组成,其类图关系如下图所示:
图错误!
文档中没有指定样式的文字。
JUnit测试框架类结构
·junit.framework.Test:
测试接口。
·junit.framework.TestCase:
测试用例类,业务类的测试用例类只需要承继这个TestCase,根据情况编写若干个publicvoidtestXxx()方法,在方法中通过assertYyy()定制若干测试规则就可以了。
·junit.framework.TestSuite:
测试套件类,它可以将多个测试用例类捆绑在一起运行,也可以捆绑另一个测试套件。
测试固件(Fixture)
一个测试用例可以包含若干个testXxx()测试方法,测试用例测试一个或多个类API接口的正确性,当然在调用类API时,需要事先创建这个类的对象及一些关联的对象,这组对象就称为测试固件(Fixture),相当于测试用例的"工作对象"。
我们在前面说过,一个测试用例类可以包含多个testXxx()方法,在运行时,每个测试方法都对应一个测试用例类的实例。
当然,你可以在具体的testXxx()方法里声明并实例化业务类的实例,在测试完成后再销毁它们。
但是,这么一来你就要在每个testXxx()方法中都重复这些代码,因为TestCase实例被运行时,依照以下步骤运行:
1.创建测试用例的实例。
2.调用setUp()方法,执行一些初始化工作。
3.运行testXxx()测试方法。
4.调用tearDown()方法,执行销毁对象的工作。
如果测试用例类中有多个testXxx()方法,且它们都需要使用到相同的一组对象,我们可以在setUp()中实例化这组对象,并在tearDown()中销毁它们。
要编写测试固件,依照以下步骤进行:
1.创建TestCase类的子类。
2.在子类中声明若干个测试所用的对象。
3.覆盖setUp()方法,在方法中实例化这些对象。
4.覆盖tearDown()方法,释放这些对象的资源。
如下面即是一个简单的测试固件:
代码清单错误!
文档中没有指定样式的文字。
测试固件
1.publicclassMoneyTestextendsTestCase
2.{
3. privateMoneyf12CHF;//12瑞士法郎
4. privateMoneyf14CHF;//14瑞士法郎
5. privateMoneyf28USD;//28美国美元
6. protectedvoidsetUp(){
7. f12CHF=newMoney(12,"CHF");
8. f14CHF=newMoney(14,"CHF");
9. f28USD=newMoney(28,"USD");
10. }
11. protectedvoidtearDown(){}
12.}
第3~5行声明了3个Money类对象(测试固件),在setUp()方法中实例化这3个对象(第7~9行),由于这些对象可以被垃圾进行直接回收,所以在tearDown()中不做任何操作。
测试用例(TestCase)
有了测试固件,就可以开始编写测试用例的测试方法了。
当然你也可不需要测试固件而直接编写测试用例方法。
下面我们在测试固件的基础上添加测试用例方法testMoneyBag(),代码如下所示:
代码清单测试用例方法
1.publicclassMoneyTestextendsTestCase
2.{
3. privateMoneyf12CHF;//12瑞士法郎
4. privateMoneyf14CHF;//14瑞士法郎
5. privateMoneyf28USD;//28美国美元
6. protectedvoidsetUp(){
7. f12CHF=newMoney(12,"CHF");
8. f14CHF=newMoney(14,"CHF");
9. f28USD=newMoney(28,"USD");
10. }
11. publicvoidtestMoneyBag()
12. {
13. Moneybag[]={f26CHF,f28USD};
14. MoneyBagexpected=newMoneyBag(bag);
15. assertEquals(expected,f12CHF.add(f28USD.add(f14CHF)));
16. }
17. protectedvoidtearDown(){}
18.}
测试方法都必须以test为前缀,且必须是publicvoid的,运行器以此为反射查找规则找到这些测试用例方法。
在一个方法中可以包括多个assertYyy()方法,每个assertYyy()方法都是一个测试规则。
像第15行的assertYyy()断言方法即为测试Money的add()方法和MoneyBag类正确性的测试规则。
你可以在MoneyTest中添加多个publicvoidtestXxx()方法,运行器为每个方法生成一个测试用例实例,分别运行。
测试套件(TestSuite)
如果每次只能运行一个测试用例,那么又陷入了我们前面所谈到的传统测试的窘境:
手工去运行一个个测试用例,测试套件专门为解决这一问题而来。
它通过TestSuite对象将多个测试用例组装成到一个测试套件,则测试套件批量运行。
需要特殊指出的是,可以把一个测试套件整个添加到另一个测试套件中,就象小筐装进大筐里变成一个箧一样。
测试套件类也通过承继TestCase类实现,只不过它提供了一个publicstaticTestsuite()静态方法,在该方法中将多个测试用例捆绑组装在一起。
一个典型的测试套件代码如下所示:
代码清单错误!
文档中没有指定样式的文字。
测试套件
1.publicclassMoneyTestSuiteextendsTestCase
2.{
3. publicTestSuite1(Strings)
4. {
5. super(s);
6. }
7. publicstaticTestsuite()
8. {
9. TestSuitesuite=newTestSuite();
10. suite.addTestSuite(MoneyTest.class);
11. suite.addTestSuite(MoneyBag.class);
12. returnsuite;
13. }
14.}
在第9行中声明并实例化了一个TestSuite,在第10、11行分别加入一个测试用例。
你可以通过suite.addTest(Testt)方法添加一个套件。
这样运行这个套件就可以自动运行所有测试用例的测试方法了。
测试运行器
JUnit提供了3个标准的测试运行器运行这些测试用例或测试套件,这3个测试运行器分别是:
·junit.textui.TestRunner:
文本测试运行器。
·junit.awtui.TestRunner:
使用AWT组件界面的测试运行器。
·junit.swingui.TestRunner:
使用Swing组件界面的测试运行器。
下面是基于AWT组件的测试运行器,如下图所示:
图错误!
文档中没有指定样式的文字。
AWT测试运行器
·Testclassname:
指定测试用例类和测试套件类。
·一个进度条:
表示运行测试的执行进度,进度条下是正确、错误、失败的测试统计数。
·ErrorandFailures:
列出了测试错误和失败的列表,点选其中的一个选项时,JUnit在窗口底部列出错误跟踪迹。
提示:
JBuilder提供了方便的运行测试用例和测试套件类的方法,你只须点击鼠标右键就可直接调用了。
此外,JBuilder提供了一个JBTestRunner测试运行器,在功能和易用性上非JUnit提供的测试运行器所能媲美。
JBuilder支持JUnit所提供的两个测试运行器:
junit.textui.TestRunner和junit.swingui.TestRunner。
业务类介绍
为了便于讲解,拟通过两个简单的业务类引出测试用例,一个是分段函数类,另一个是字符串处理类,在这节里我们先来熟悉这两个业务类。
为了便于讲解,拟通过两个简单的业务类引出测试用例,一个是分段函数类,另一个是字符串处理类,在这节里我们先来熟悉这两个业务类。
分段函数类
分段函数Subsection类有两个函数,sign()是一个符号函数,而getValue(intd)函数功能如下:
当d<-2时,值为abs(d);
当-2≤d<2且d!
=0时,值为d*d;
当d=0时,值为100;
当2≤d时,值为d*d*d。
其代码如下图所示:
代码清单错误!
文档中没有指定样式的文字。
分段函数
1.packagechapter25;
2.
3.publicclassSubsection
4.{
5. publicstaticintgetValue(intd){
6. if(d==0){
7. return100;
8. }elseif(d<-2){
9. returnMath.abs(d);
10. }elseif(d>=-2&&d<2){
11. returnd*d;
12. }else{//d>=2
13. //if(d>32){
14. //returnInteger.MAX_VALUE;
15. //}
16. returnd*d*d;
17. }
18.}
19.
20.publicstaticintsign(doubled){
21. if(d<0){
22. return-1;
23. }elseif(d>0){
24. return1;
25. }else{
26. return0;
27. }
28.}
29.}
在getValue()方法中,当d>32时,d*d*d的值将超过int数据类型的最大值(32768),所以当d>32时,理应做特殊的处理,这里我们特意将这个特殊处理的代码注释掉(第13~15行),模拟一个潜在的Bug。
字符串处理类
由于标准JDK中所提供的String类对字符串操作功能有限,而字符串处理是非常常用的操作,所以一般的系统都提供了一个自己的字符串处理类。
下面就是一个字符串处理类,为了简单,我们仅提供了一个将字符串转换成数组的方法string2Array(),其代码如下所示:
代码清单错误!
文档中没有指定样式的文字。
字符串处理类
1.packagechapter25;
2.publicclassStringUtils
3.{
4. publicstaticString[]string2Array(Stringstr,charsplitChar,booleantrim){
5. if(str==null){
6. returnnull;
7. }else{
8. StringtempStr=str;
9. intarraySize=0;//数组大小
10. String[]resultArr=null;
11. if(trim){//如果需要删除头尾多余的分隔符
12. tempStr=trim(str,splitChar);
13. }
14. arraySize=getCharCount(tempStr,splitChar)+1;
15. resultArr=newString[arraySize];
16. intfromIndex=0,endIndex=0;
17. for(inti=0;i 18. endIndex=tempStr.indexOf(splitChar,fromIndex); 19. if(endIndex==-1){ 20. resultArr[i]=tempStr.substring(fromIndex); 21. break; 22. } 23. resultArr[i]=tempStr.substring(fromIndex,endIndex); 24. fromIndex=endIndex+1; 25. } 26. returnresultArr; 27. } 28. } 29. 30. //将字符串前面和后面的多余分隔符去除掉。 31. privatestaticStringtrim(Stringstr,charsplitChar){ 32. intbeginIndex=0,endIndex=str.length(); 33. for(inti=0;i 34. if(str.charAt(i)! =splitChar){ 35. beginIndex=i; 36. break; 37. } 38. } 39. for(inti=str.length();i>0;i--){ 40. if(str.charAt(i-1)! =splitChar){ 41. endIndex=i; 42. break; 43. } 44. } 45. returnstr.substring(beginIndex,endIndex); 46. } 47. 48. //计算字符串中分隔符中个数 49. privatestaticintgetCharCount(Stringstr,charsplitChar){ 50. intcount=0; 51. for(inti=0;i 52. if(str.charAt(i)==splitChar){ 53. count++; 54. } 55. } 56. returncount; 57. } 58.} 除对外APIstring2Array()外,类中还包含了两个支持方法。 trim()负责将字符前导和尾部的多余分隔符删除掉(第31~46行);而getCharCount()方法获取字符中包含分隔符的数目,以得到目标字符串数组的大小(第49~57行)。 创建测试用例 JBuilder为测试用例类指定了一个默认的类名,即Test<业务类名>,包名和业务类包名一致。 接受默认的值,直接按Finish创建TestSubsection测试用例类。 我们先为Subsection类创建测试用例。 1.在编辑器中打开Subsection.java文件,使其处理激活态。 2.File->New...->Test->在Test页的对象库中双击TestCase图标,启动创建测试用例的向导,如下图所示: 图错误! 文档 中没有指定样式的文字。 指定测试的方法 ·Selectclass: 测试的目标类,默认为当前编辑器中打开的类,也可以通过其后的…按钮选择工程中其他的类。 ·Avaiablemethods: 列出了测试目标类的所有public、protected和默认可视域的方法,private方法不列出。 只要你测试了前三者的方法,private也被间接测试到了。 这里,我们选择getValue()和sign()方法。 点击Next到下一步。 3.设置测试用例类的类名。 图错误! 文档中没有指定样式的文字。 指定测试用例类的名称 JBuilder为测试用例类指定了一个默认的类名,即Test<业务类名>,包名和业务类包名一致。 接受默认的值,直接按Finish创建TestSubsection测试用例类。 实战经验: 虽然在物理上,业务类和测试用例类被放在不同目录下,但在工程窗格的资源树中,业务类和测试用例还是挤在了一起。 如果一个包下有多个业务类,加上它们相应的测试用例类,将显得更加拥挤不堪。 所以最好将测试用例放到不同的包中,如com.super.bdbj包中的所有业务类的测试用例放到test.super.bdbj目录下,这样将彻底解决测试用例和业务类的物理和逻辑上的分离,使工程窗格中的资源树更加整洁明了。 TestSubsection类的代码如下所示: 代码清单错误! 文档中没有指定样式的文字。 向导生成的TestSubsection类 1.packagechapter25; 2. 3.importjunit.framewor
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- JBuilder0520 单元测试 体验