单元测试与JUNIT_第1页
单元测试与JUNIT_第2页
单元测试与JUNIT_第3页
单元测试与JUNIT_第4页
单元测试与JUNIT_第5页
已阅读5页,还剩70页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、单元测试与JUNIT主要内容1. 单元测试介绍 2. 单元测试 Quick Start3. 使用JUNIT4. 测试的一些技巧5. 边界条件6. MOCK对象简介7. 单元测试与软件设计1.单元测试介绍 1.1什么是单元测试 单元测试是开发者写的一小段代码,用于检验被测代码的一个很小的、明确的功能是否正确。通常而言,一个单元测试是用于判断某个特定条件下某个特定的函数的行为。 执行单元测试,是为了证明某段代码的行为确定和开发者所期望的一致。1.2单元测试的目的 及早发现软件开发过程中实现或者设计带来的缺陷 跟踪详细设计文档中设计的实现,发现详细设计文档中存在的错误 验证单元代码和详细设计文档的一

2、致性 发现在编码过程中引入的错误单元测试标准是什么 单元测试标准通常为详细设计说明书 但是在没有详细设计说明书的情况下可以以注释为测试标准单元测试过程 单元测试计划 单元测试设计 单元测试实现 单元测试执行 单元测试评估单元测试计划 时间表 工作量 任务分配 资源安排 测试工具 结束标准 风险分析 风险应对 输出单元测试计划文档单元测试设计 对哪些单元进行测试 被测单元的关系 被测单元与其他模块的关系 测试策略选择 如何设计测试用例 如何设计单元测试代码 输出单元测试用例文档单元测试实现 编写测试用例 编写测试规程 测试脚本编写 测试驱动构建 桩构建 输出测试用例 输出测试规程 输出测试代码和

3、脚本单元测试执行 搭建测试环境 执行测试脚本 记录测试结果 跟踪缺陷 回归测试 输出单元测试报告单元测试策略 自顶向下的单元测试 方法 先对最顶层的单元进行测试,把顶层单元所调用的单元做成桩模块。其次对第二层单元进行测试,使用上面已测试的单元做驱动模块。依次类推直至测试完所有的模块。 优点 可以节省驱动函数开发的工作量,测试效率较高 缺点 随着被测单元一个个的加入,测试过程将变得复杂,并且开发和维护的成本将增加。 自底向上的单元测试 孤立的单元测试 混合的单元测试 自底向上的单元测试 先对最底层的单元进行测试,模拟主调单元构建驱动模块。然后再对上面一层做单元测试,用下面已经测试通过的模块做桩模

4、块。依次类推,直至测试完所有的模块。 优点 可以节省桩模块开发的工作量,测试效率高 缺点 不是纯粹的单元测试,底层函数的测试质量对上层函数的测试将产生很大的影响。 孤立的单元测试 方法 不考虑模块和模块之间的关系,为每个模块设立桩模块和驱动模块。每个模块进行独立的单元测试 优点 该策略最简单,最容易操作。可以达到很高的覆盖率。似乎纯粹的单元测试 缺点 该策略效率很低,需要构建大量的驱动和桩 混合的单元测试 自顶向下和自底向上的测试策略综合了集成的概念,随着单元测试的进行,可以看到系统一个初步集成的概貌,但是测试覆盖率会越来越难保证。并且在每个单元测试之前必须保证相关的单元的正确性。孤立的测试策

5、略比较独立,覆盖率容易保证,并且可以并行进行,但工作量大。所以采用混合方法比较好。单元测试用例设计 单元测试用例设计方法 黑盒 白盒 单元测试用例编写思路 为系统运行起来设计测试用例 为正向测试设计用例 为逆向测试设计用例 为满足特殊需求而设计用例 为代码覆盖而设计测试用例 单元测试用例设计五要点 单元接口 局部数据结构 独立路径 出错处理 边界条件 理解需求和设计 设计测试用例 搭建单元测试环境 执行测试 补充和完善测试用例 分析结果,给出评价1.3 我需要做什么呢 它的行为和我的期望一致吗? 它的行为一直和我的期望一致吗? 我可以依赖单元测试吗? 单元测试说明我的意图了吗?1.4不写单元测

6、试的借口 编写单元测试太花时间了 运行测试的时间太长了 测试代码并不是我的工作 我并不清楚代码的行为,所以也就无从测试 但是这些代码都能编译通过 公司请我是为了写代码,而不是写单元测试 如果我让测试员失去工作,我会觉得内疚 公司不会让我在真实系统中运行单元测试2.单元测试 Quick Start2.1测试对象寻找数组中的最大数:public class Largest public static int largest(int list) int index, max=Integer.MAX_VALUE; for (index = 0; index max) max = listindex;

7、return max; 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.java Account.java准备要测试的条件调用要测试的方法验证被测试方法的行为是否和结果一致完成后清理各种资源testCreateAccount()testCreateAccountDef()testCreateAcco

8、untDup()createAccount()3.2 JUNIT的各种断言lassertEquals(String message,expected,actual)lassertEquals(String message,expected,actual,tolerance)lassertNull (String message,Object object)lassertNotNull (String message,Object object)lassertSame (String message,expected,actual)lassertNotSame (String message,e

9、xpected,actual)lassertTrue (String message,boolean condition)lassertFalse (String message,boolean condition)lfail (String message)l自定义断言3.3 JUNIT框架import junit.framework.*; /引入测试包public class TestSimple extends TestCase /继承 TestCase public TestSimple(String name) /默认使用父类的实例化方法 super(name); public vo

10、id testAdd() /书写以test开头的断言,凡是以test开头的都会 /被junit自动运行 assertEquals(2, 1+1); public void testAdds() /一个测试方法里也可以有多个断言 assertEquals(2, 1+1); assertEquals(4, 2+2); assertEquals(-8, -12+4); 测试类也能调用其他测试类:单独的类、包、甚至完整的一个系统。这可以通过创建test suite来取得。任何测试类都能包含一个名为suite的静态方法: Public static Test suite(); 现假设有第2个类TestC

11、lassTwo,它使用brute-force算法来寻找旅行销售商Bob的最短行程。但这个算法是复杂度是指数级的。默认情况下你不想包括这些测试。3.4 JUNIT测试的组成(1)import junit.framework.*;public class TestClassTwo extends TestCase public TestClassTwo(String method) super(method); public void testLongRunner() public void testShortTest() public void testAnotherShortTest() pu

12、blic static Test suite() TestSuite suite = new TestSuite(); suite.addTest(new TestClassTwo(“testShortTest”);/装入测试方法 suite.addTest(new TestClassTwo(testAnotherShortTest); return suite; 3.4 JUNIT测试的组成(2)import junit.framework.*;public class TestClassComposite extends TestCase public TestClassComposite

13、(String method) super(method); static public Test suite() TestSuite suite = new TestSuite();/执行第一个测试类所有的测试 suite.addTestSuite(TestClassOne.class); /执行第二个测试类中指定的测试 suite.addTest(TestClassTwo.suite(); return suite; 假设对于每个测试,你都需要某种数据库连接,这时,你不需要在每个测试方法中重复建立连接和释放连接了,而只须在setup和teardown方法中分别建立和释放连接。 执行每个测试

14、方法之前会执行setup,之后会执行teardownJUnit和异常 对测试而言,下面两种异常我们可能会感兴趣: 从测试代码抛出的可预测异常。 由于某个某块(或代码)发生严重错误,而抛出的不可预测异常。 如有一个名为sortMyList()的方法,如果传入参数是一个nulllist,那么我们希望该方法抛出一个异常。在这种情况下,我们就需要显式地测试这一点。 assertTure(true)表示“我预期控制流程会达到这个地方。 Junit可以捕获任何异常,并且把它报告为一个错误,这些都不需要你的参与。更好的是,Junit不只是让一个断言失败,而是能够跟踪整个堆栈,并且报告bug的堆栈调用顺序,当

15、你需要查找一个失败测试的原因时,这将非常有用。4.测试哪些内容测试哪些内容4.1测试内容(Right-BICEP)Right-结果是否正确?B-是否所有的边界条件都是正确的?I-能查一下反向关联吗?C-能使用其它手段交叉检查一下结果吗?E-你是否可以强制错误条件发生?P-是否满足性能要求? 完全伪造或者不一致的输入数据,例如一个名为“!*w:gjagja;,/.d;”的文件。 格式错误的数据,例如没有顶层域名的电子邮件地址,如fredfoobar 空值或不完整的值 一些与意料中的合理值相去甚远的数值。如一个岁数为10000岁。 如果要求的是一个不允许出现重复数值的list,但是传入的是一个存在

16、重复数值的list如果要求的是一个有序list,但是传入的是一个无序list;或者反之事情到达的次序是错误的,或者碰巧和期望的次序不一致,如未登陆系统之前,就尝试打印文档。可能的边界值反向关联 如对结果进行平方的方式来检查一个计算平方根的函数,然后测试结果是否和原数据很接近。 类似地,为了检查某条记录是否成功地插入了数据库,你也可以通过查询这条记录来验证。其它手段交叉检查 通常计算一个量会有一种以上的算法。我们可能会基于运行效率或者其他的特性,来选择算法,那是我们要在产品中使用的,但在测试时可以使用剩下的算法来做交叉测试。其它手段交叉检查 另一种办法,使用类本身不同组成部分的数据,并且确信它们

17、能“合起来”。如,正在做一个图书馆的数据系统。在这个系统中,对每一本具体的书,它的数量永远是平衡的。 我们可以用一种数量检查另一种数量。强制产生错误条件 真实世界中,错误总是会发生:磁盘会满,网络连线会断开,电子邮件会多得像掉进了黑洞,而程序会崩溃。你应当能够通过强制引发错误,来测试你的代码是如何处理所有这些真实世界中的问题的。强制产生错误条件性能问题 不是性能本身 如:“随着输入尺寸慢慢变大,问题慢慢变复杂”的趋势。 确保性能曲线能够保持稳定5. CORRECT边界条件5.1 边界条件o 思考public int calculate(int a,int b)return a/(a+b);5.

18、2 边界条件o 一致性(Conformance)o值是否和预期的一致o 有序性(Ordering)o值是否如应该的那样,是有序或无序o 区间性(Range)o值是否位于合理的最小值和最大值之内。o 引用,耦合性(Reference)o代码是否引用了一些不在代码本身控制范围之内的外部资源5.2 边界条件o 存在性(Existence):值是否存在o 基数性(Cardinality)o是否恰好有足够的值o 时间性(Time)区间性 如果数据不能像你期望的那样与结构相一致,将会出现什么情况?象这种情况,你就需要测试你的结果并确保其一致性。(一致性) 任何一个搜索程序都应该针对搜索目标位于最前或最后的

19、条件做测试。(有序性) 如果这种情况可能发生,并且在发生的时候,你的程序需要处理她,那么你就需要测试这种情况。耦合性 如,网站上一个用来显示用户记录的方法,可能要求用户先登录。 栈的pop()方法要求一个非空的栈。 给汽车换挡。 前条件、后条件存在性 通过询问:“给定的事物存在吗?” 对于你传入或者维护的值,先询问如果值不存在如果它为null、或者等于0,方法的行为将会怎样? 面对这些不存在的数据,java库的许多方法会抛出异常。然而要调试一个隐藏在库深处的运行期异常通常并不容易。 在期望值不存在的时候,大多数方法都会失败,但这可能并不是你所期望的结果。因此,你可以对这些情况进行测试,查看当网

20、络不通、文件不存在的时候,又会发生什么事情。确认你的方法处理了“不存在”的情况。 一年中的每一天都是24小时吗? 并发问题练习(思考栈的测试方法)public interface StackExercise public String pop() throws StackEmptyException; public void push(String item); public String top() throws StackEmptyException; public boolean isEmpty();答案(思考栈的测试方法)o 对于空栈 isEmpty=true,pop(),top(),

21、抛异常。o push(“字符”),top(),返回刚压入的字符串,isEmpty()=false。o 多次调用push();验证每一次top()。o push(null),top()=null。o 发生异常后,栈仍可以使用。6. MOCK对象简介对象简介6.1 MOCK对象 概念: MOCK对象是真实对象在调试期间的替代品。简单的替换 一般,我们建议对应用程序范围外的功能调用进行包装。 因为被测试代码只会通过接口来引用对象,所以它完全不知道它引用的究竟是真实对象还是mock 对象。 在产品环境(卖给客户的真正的代码)中,当初始化这个类的对象时,传入的是一个真实的systemEnvironmen

22、t,而另一方面,测试代码传入的是则是mockSystemEnvironment。6.2 什么情况下使用MOCK对象o 真实对象行为不确定(如股票行情)。o 真实对象很难被创建。o 真实对象的某些行为很难被触发。o 真实对象令程序的运行很慢。o 真实对象有(或者是)用户界面。o 测试含有回调函数。o 真实对象并不存在。6.3 使用MOCK对象的步骤o 使用一个接口来描述这个对象。o 为产品代码实现这个接口。o 以测试为目的,在MOCK对象中实现这个接口。练习:实现MP3的MOCK对象import java.util.ArrayList;public interface Mp3Player pub

23、lic void play();public void pause();public void stop();public double currentPosition();public String currentSong();public void next();public void prev();public boolean isPlaying();public void loadSongs(ArrayList names);7. 单元测试与软件设计单元测试与软件设计7.1 软件设计关注的几个层面o 通过面向测试的软件设计,更好地分离关注点。o 通过测试驱动的方法,改善接口设计。o 确

24、立和局部化验证的责任。7.2 面向测试的软件设计例:public void sleepUtilNextHour throws InterrupedExceptionint howlong;计算休眠时间的一系列代码Thread.sleep(howlong);Return; 等一个小时? 设一个计时器,调用这个函数,等结束后回来再检查时间,如果失败了,再来处理一下,重新测试?7.3 面向测试的软件设计重构代码public void sleepUtilNextHour throws InterrupedExceptionint howlong=milliSecondsTONextHour(new Date();Thread.sleep(howlong);Return;测试:asserEquals(10000, mil

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论