第五讲单元测试与Junit

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

单元测试第五讲主要内容1.单元测试介绍2.单元测试QuickStart3.使用JUNIT4.测试的一些技巧5.边界条件6.MOCK对象简介7.单元测试与软件设计1.单元测试介绍•1.1什么是单元测试•单元测试是开发者写的一小段代码,用于检验被测代码的一个很小的、明确的功能是否正确。通常而言,一个单元测试是用于判断某个特定条件下某个特定的函数的行为。•执行单元测试,是为了证明某段代码的行为确定和开发者所期望的一致。1.2单元测试的目的•及早发现软件开发过程中实现或者设计带来的缺陷–跟踪详细设计文档中设计的实现,发现详细设计文档中存在的错误–验证单元代码和详细设计文档的一致性–发现在编码过程中引入的错误单元测试标准是什么•单元测试标准通常为详细设计说明书•但是在没有详细设计说明书的情况下可以以注释为测试标准单元测试过程•单元测试计划•单元测试设计•单元测试实现•单元测试执行•单元测试评估单元测试计划•时间表•工作量•任务分配•资源安排•测试工具•结束标准•风险分析•风险应对•输出单元测试计划文档单元测试设计•对哪些单元进行测试•被测单元的关系•被测单元与其他模块的关系•测试策略选择•如何设计测试用例•如何设计单元测试代码•输出单元测试用例文档单元测试实现•编写测试用例•编写测试规程•测试脚本编写•测试驱动构建•桩构建•输出测试用例•输出测试规程•输出测试代码和脚本单元测试执行•搭建测试环境•执行测试脚本•记录测试结果•跟踪缺陷•回归测试•输出单元测试报告单元测试策略•自顶向下的单元测试–方法先对最顶层的单元进行测试,把顶层单元所调用的单元做成桩模块。其次对第二层单元进行测试,使用上面已测试的单元做驱动模块。依次类推直至测试完所有的模块。–优点可以节省驱动函数开发的工作量,测试效率较高–缺点随着被测单元一个个的加入,测试过程将变得复杂,并且开发和维护的成本将增加。•自底向上的单元测试•孤立的单元测试•混合的单元测试•自底向上的单元测试–先对最底层的单元进行测试,模拟主调单元构建驱动模块。然后再对上面一层做单元测试,用下面已经测试通过的模块做桩模块。依次类推,直至测试完所有的模块。–优点可以节省桩模块开发的工作量,测试效率高–缺点不是纯粹的单元测试,底层函数的测试质量对上层函数的测试将产生很大的影响。•孤立的单元测试–方法不考虑模块和模块之间的关系,为每个模块设立桩模块和驱动模块。每个模块进行独立的单元测试–优点该策略最简单,最容易操作。可以达到很高的覆盖率。似乎纯粹的单元测试–缺点该策略效率很低,需要构建大量的驱动和桩•混合的单元测试–自顶向下和自底向上的测试策略综合了集成的概念,随着单元测试的进行,可以看到系统一个初步集成的概貌,但是测试覆盖率会越来越难保证。并且在每个单元测试之前必须保证相关的单元的正确性。孤立的测试策略比较独立,覆盖率容易保证,并且可以并行进行,但工作量大。所以采用混合方法比较好。单元测试用例设计•单元测试用例设计方法–黑盒–白盒•单元测试用例编写思路–为系统运行起来设计测试用例–为正向测试设计用例–为逆向测试设计用例–为满足特殊需求而设计用例–为代码覆盖而设计测试用例•单元测试用例设计五要点–单元接口–局部数据结构–独立路径–出错处理–边界条件•理解需求和设计•设计测试用例•搭建单元测试环境•执行测试•补充和完善测试用例•分析结果,给出评价1.3我需要做什么呢•它的行为和我的期望一致吗?•它的行为一直和我的期望一致吗?•我可以依赖单元测试吗?•单元测试说明我的意图了吗?1.4不写单元测试的借口•编写单元测试太花时间了•运行测试的时间太长了•测试代码并不是我的工作•我并不清楚代码的行为,所以也就无从测试•但是这些代码都能编译通过•公司请我是为了写代码,而不是写单元测试•如果我让测试员失去工作,我会觉得内疚•公司不会让我在真实系统中运行单元测试2.单元测试QuickStart2.1测试对象寻找数组中的最大数:publicclassLargest{publicstaticintlargest(int[]list){intindex,max=Integer.MAX_VALUE;for(index=0;indexlist.length-1;index++){if(list[index]max){max=list[index];}}returnmax;}}2.2设计测试排序测试:【9,7,8】→9【7,9,8】→9【7,8,9】→9重复值:【7,9,8,9】→9单值:【1】→1负值:【-9,-8,-7】→-7….空值2.3执行测试•执行测试并修正错误•理解单元测试3.使用JUNITJunit简介Junit的定位Junit的安装Junit的体系结构Junit的使用3.1构建单元测试TestAccount.javaAccount.java•准备要测试的条件•调用要测试的方法•验证被测试方法的行为是否和结果一致•完成后清理各种资源testCreateAccount()testCreateAccountDef()testCreateAccountDup()createAccount()3.2JUNIT的各种断言assertEquals([Stringmessage],expected,actual)assertEquals([Stringmessage],expected,actual,tolerance)assertNull([Stringmessage],Objectobject)assertNotNull([Stringmessage],Objectobject)assertSame([Stringmessage],expected,actual)assertNotSame([Stringmessage],expected,actual)assertTrue([Stringmessage],booleancondition)assertFalse([Stringmessage],booleancondition)fail([Stringmessage])自定义断言3.3JUNIT框架importjunit.framework.*;//引入测试包publicclassTestSimpleextendsTestCase{//继承TestCasepublicTestSimple(Stringname){//默认使用父类的实例化方法super(name);}publicvoidtestAdd(){//书写以test开头的断言,凡是以test开头的都会//被junit自动运行assertEquals(2,1+1);}publicvoidtestAdds(){//一个测试方法里也可以有多个断言assertEquals(2,1+1);assertEquals(4,2+2);assertEquals(-8,-12+4);}}•测试类也能调用其他测试类:单独的类、包、甚至完整的一个系统。这可以通过创建testsuite来取得。任何测试类都能包含一个名为suite的静态方法:•PublicstaticTestsuite();•现假设有第2个类TestClassTwo,它使用brute-force算法来寻找旅行销售商Bob的最短行程。但这个算法是复杂度是指数级的。默认情况下你不想包括这些测试。3.4JUNIT测试的组成(1)importjunit.framework.*;publicclassTestClassTwoextendsTestCase{publicTestClassTwo(Stringmethod){super(method);}publicvoidtestLongRunner(){…}publicvoidtestShortTest(){…}publicvoidtestAnotherShortTest(){…}publicstaticTestsuite(){TestSuitesuite=newTestSuite();suite.addTest(newTestClassTwo(“testShortTest”));//装入测试方法suite.addTest(newTestClassTwo(testAnotherShortTest));returnsuite;}}3.4JUNIT测试的组成(2)importjunit.framework.*;publicclassTestClassCompositeextendsTestCase{publicTestClassComposite(Stringmethod){super(method);}staticpublicTestsuite(){TestSuitesuite=newTestSuite();//执行第一个测试类所有的测试suite.addTestSuite(TestClassOne.class);//执行第二个测试类中指定的测试suite.addTest(TestClassTwo.suite());returnsuite;}}•假设对于每个测试,你都需要某种数据库连接,这时,你不需要在每个测试方法中重复建立连接和释放连接了,而只须在setup和teardown方法中分别建立和释放连接。•执行每个测试方法之前会执行setup,之后会执行teardownJUnit和异常•对测试而言,下面两种异常我们可能会感兴趣:–从测试代码抛出的可预测异常。–由于某个某块(或代码)发生严重错误,而抛出的不可预测异常。–如有一个名为sortMyList()的方法,如果传入参数是一个nulllist,那么我们希望该方法抛出一个异常。在这种情况下,我们就需要显式地测试这一点。•assertTure(true)表示“我预期控制流程会达到这个地方。•Junit可以捕获任何异常,并且把它报告为一个错误,这些都不需要你的参与。更好的是,Junit不只是让一个断言失败,而是能够跟踪整个堆栈,并且报告bug的堆栈调用顺序,当你需要查找一个失败测试的原因时,这将非常有用。4.测试哪些内容4.1测试内容(Right-BICEP)•Right-结果是否正确?•B-是否所有的边界条件都是正确的?•I-能查一下反向关联吗?•C-能使用其它手段交叉检查一下结果吗?•E-你是否可以强制错误条件发生?•P-是否满足性能要求?•完全伪造或者不一致的输入数据,例如一个名为“!*w:gjagja;;,/.d;”的文件。•格式错误的数据,例如没有顶层域名的电子邮件地址,如fred@foobar•空值或不完整的值•一些与意料中的合理值相去甚远的数值。如一个岁数为10000岁。•如果要求的是一个不允许出现重复数值的list,但是传入的是一个存在重复数值的list•如果要求的是一个有序list,但是传入的是一个无序list;或者反之•事情到达的次序是错误的,或者碰巧和期望的次序不一致,如未登陆系统之前,就尝试打印文档。可能的边界值反向关联•如对结果进行平方的方式来检查一个计算平方根的函数,然后测试结果是否和原数据很接近。•类似地,为了检查某条记录是否成功地插入了数据库,你也可以通过查询这条记录来验证。其它手段交叉检查•通常计算一个量会有一种以上的算法。我们可能会基于运行效率或者其他的特性,来选择算法,那是我们要在产品中使用的,但在测试时可以使用剩下的算法来做交叉测试。其它手段交叉检查•另一种办法,使用类本身不同组成部分的数据,并且确信它们能“合起来”。如,正在做一个图书馆的数据系统。在这个系统中,对每一本具体的书,它的数量永远是平衡的。•我们可以用一种数量检查另一种数量。强制产生错误条件•真实世界中,错误总是会发生:磁盘会满,网络连线会断开,电子邮件会多得像掉进了黑洞,而程序会崩溃。你应当能够通过强制引发错误,来测试你的代码是如何处理所有这些真实世界中的问题的。强制产生错误条件性能问题•不是性能本身•如:“随着输入尺寸慢慢变大,问题慢慢变复杂”的趋势。•确保性能曲线能够保持稳定5.CORRECT边界条件5.1边

1 / 75
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功