这是段单元测试的方法有哪些代码,左边图是被测代码,怎么改才能以数组形式把测试用例全部输入?

之前有将基础的软件测试知识做了一个总结,但比较潦草,很多内容只是一笔带过,快到年底了,自己也有个写年终知识总结文档的计划,就将基础的理论知识重新整理一番。。。

有人问我,这些都是百度能百度到的知识,为什么要写?可能个人的角度不同吧,我是希望每个阶段都将自己的收获做一个总结,自己也能不断提升;

毕竟,百度出来的只是百度的,自己写的才是自己的;就像认识的一个家伙说过一句话:快餐时代,需要沉淀。。。。。。

定义:计算机系统中与硬件相互依存的一部分(程序+数据+相关文档)

程序:按事先设计的功能和性能要求执行的指令序列

数据:使程序能正常操纵信息的数据结构

文档:与程序开发、维护和使用有关的图文资料

主要分为软件开发技术(方法+过程+工具+环境)和软件开发管理

可行性研究和计划(立项)

实现(开发阶段;包含单元测试)

确认测试(系统测试,验收回归测试)

使用和维护(上线使用及日常更新维护)

定义:软件质量保证的一种手段

目的:发现错误以及避免这些错误的发生,使产品达到完美

概念:是软件工程中的一个非常重要的环节,是开发项目整体的一部分。是有计划有组织的,是伴随软件工程的诞生而诞生的,软件测试不是万能的,不可能发现全部缺陷,软件测试是有局限性的。

②、用新旧两个系统做平行处理检查

③、软件测试自动化工具测试

6、软件测试阶段有哪些任务

①、制定测试大纲(测试计划)

②、制作测试数据(测试方案)

③、单元测试(程序测试,一般由开发人员进行)

⑥、集成测试(子系统测试)

⑨、测试报告及向下阶段提交系统运行、维护用户手册

①、尽早的、不断地进行测试

②、测试用例由输入数据和与之对应的输出结果组成,应包括合理和不合理的输入条件

③、开发者应尽量避免检查自己的程序

④、设计测试用例时,应包括合理和不合理的输入条件

⑤、充分注意测试中的集群现象,严格执行测试计划,排除测试的随意性

⑥、对每一个测试结果做全面检查

⑦、妥善保存测试计划,方案,用例,BUG记录及最终分析报告等文档

8、软件测试工作流程图

编码&单元测试阶段

概念:为了提高工作效率,节省人力和成本,把人为驱动的测试转化为机器执行

10、自动化测试的过程

框架搭建(附带工具选择)

测试用例设计(编写测试用例或开发测试脚本,并文档化)

测试——调试测试(针对自动化测试脚本)

评估(评估测试结果并改进测试过程)

11、自动化测试的优点

①、能执行更多更频繁的测试, 使某些测试任务执行方式更高效

②、能执行一些手动测试困难或者不能做的测试

③、任务自动化,使测试人员投入更多精力设计测试用例,提高测试准确性和人员积极性

④、具有一致和可重复性特点,更客观,提高软件信任度,仍存在一定局限

⑤、不能取代手工测试,不能自动化所有的测试(如只是偶尔执行测试,或需求经常变动,不稳定,或者需要大量手工参与时)

⑥、自动化测试工具只能执行命令,而手工可以在测试中判断测试的输入是否正确,以及改进测试,还可处理意外事件

⑦、对质量依赖较大,在确保质量的前提下,实施自动化才有意义

⑧、自动化测试需要在整个测试系统成熟稳定后,工作效率才会随着测试执行次数的增加而提高

⑨、自动化测试的成本可能高于手工测试

录制/回放(依赖工具)

13、自动化测试的级别

⑤、使用动作词的测试自动化

14、自动化测试方案选择需要考虑的方面

①、项目的影响(能否帮助项目进度、覆盖率、风险)

②、复杂度(是否容易实现,包括数据和其他环境等)

③、时间(实现自动化需要多少时间)

④、早期需求和代码的稳定性(需求或代码能否证明是在范围内变化的)

⑤、维护工作量(代码能否能长期保持相对稳定)

⑥、覆盖率(自动化测试能否覆盖程序的关键特性和功能)

⑦、资源(是否拥有足够的人力、硬件和数据资源来运行自动化测试)

⑧、执行(负责执行的人员是否有足够的技能和时间去运行)

15、自动化测试的重点

①、搭建测试环境,测试场景

④、自动化测试的流程以及执行

16、自动化测试需要解决的问题

定义:按照程序内部结构,逻辑驱动测试程序

目的:检测产品内部动作是否按照设计说明书的规范进行,检验程序的每条路径是否都能按照预定要求进行工作

用代码内部的分支,路径,条件,使程序设计的控制结构导出测试用例

①、保证一个模块中所有路径至少被测试一次

②、所有逻辑值都要测试真和假两种情况

③、检查程序内部的数据结构是否有效

④、检查上下边界及可操作范围内运行所有循环

①、软件共用问题的测试

界面对象(UI)→业务对象(BO)→数据管理对象(DMO)→DBserver端

DBserver端→数据管理对象(DMO)→业务对象(BO)→界面对象(UI)

①、尽量先用自动化工具来进行静态解析

②、建议先从静态测试开始(静态结构分析、代码走查、静态质量度量),然后进行动态测试(如覆盖率测试)

③、以静态分析结果作为依据,再使用代码检查和动态测试方法对静态分析结果进行进一步确认,提高测试效率及准确性

④、覆盖率测试是白盒测试的重要手段,在测试报告中可作为量化指标的依据,对于软件的重点模块,应使用多种覆盖率标准衡量代码的覆盖率

概述:主要检查代码和流图设计的一致性、代码结构的合理性、代码编写的标准性、可读性、代码的逻辑表达的正确性等方面。包括变量检查、命名和类型审查、程序逻辑审查、

程序语法检查和程序结构检查等内容。

目的:①、检查代码是否按照某种标准或规范编写的代码

②、检查代码以发现程序缺陷

③、通过检查代码容易发现程序产生的错误

④、通过检查代码来发现代码是不是流程图要求的;

⑤、通过检查代码来发现有没有遗漏的项目;

⑥、要代码易于移植,代码经常需要在不同的硬件中运行,或者使用不同的编译器编译;

⑦、要代码易于阅读、理解和维护。

项目:①、目录文件组织

定义:主要以图形的方式表现程序的内部结构(例如函数调用关系图、函数内部控制流图);通过应用程序各函数之间的调用关系展示了系统的结构,列出所有函数,用连线表示调用关系和作用。

主要分析:①、可以检查函数的调用关系是否正确

②、是否存在孤立的函数而没有被调用

③、明确函数被调用的频繁度,对调用频繁的函数可以重点检查

11、代码检查的分析与评价

①、能力(陈述经代码检查证实了的本软件的能力)

12、白盒测试常用技术(7种)

用于确定测试所执行到的覆盖项的百分比;覆盖项指作为测试基础的一个入口或属性,比如语句、分支、条件等

测试覆盖率可表示出测试的充分性,在测试分析报告中可作为量化指标的依据,测试覆盖率越高效果越好。但覆盖率不是目标,只是一种手段。

测试覆盖率包括功能覆盖和结构覆盖:

根据覆盖目标的不同和覆盖源程序语句的详尽程度,逻辑覆盖又可分为语句覆盖 、判定覆盖、条件覆盖、条件判定组合覆盖、多条件覆盖、修改条件判定覆盖、组合覆盖和路径覆盖。

面向对象的覆盖主要讨论继承上下文覆盖和基于状态的上下文覆盖。

测试覆盖准则主要讨论(ESTCA)错误敏感测试用例分析和(LCSAJ)线性代码序列与跳转。

(2)现行代码序列与跳转LCSAJ线性代码序列与条状LCSAJ是指一组顺序执行的代码,以控制流跳转为结束点。可产生4层覆盖

插桩测试是一个被广泛应用的测试方法。插桩测试就是向源程序中插入语句然后执行程序,通过打印语句,获得动态信息(我们最为关心的信息)

基本路径测试法是在程序控制流图的基础上,通过分析控制构造的环路复杂性,导出基本可执行路径集合,从而设计测试用例的方法。设计出的测试用例要保证在测试中程序的

每个可执行语句至少执行一次。重点内容如下:

程序的控制流图:描述程序控制流的一种图示方法。

程序环形复杂度:McCabe复杂性度量。从程序的环路复杂性可导出程序基本路径集合中的独立路径条数,这是确定程序中每个可执行语句至少执行一次所必须的测试用例数目的上界。

程序控制流图(可简称流图)是对程序流程图进行简化后得到的,它突出表示程序控

制流的结构。程序控制流图是描述程序控制流的一种方式。控制流图图形符号;

图形符号:圆圈代表一个结点, 表示一个或多个无分支的语句或源程序语句;

程序控制流边和点圈定的部分叫做区域。当对区域计数时,图形外的一个部分也应记为一个区域;

判断语句中的条件为复合条件时,即条件表达式由一个或多个逻辑运算符连接的逻辑表达式(a and b),则需要改变复合条件的判断为一系列只有单个条件的嵌套的判断。

基本路径测试方法是在控制流图的基础上,通过分析控制结构的环形复杂度,导出执行路径的基本集,再从该基本集设计测试用例。基本路径测试方法包括以下4个步骤:

3.1.1画出程序的控制流图。

3.1.2计算程序的环形复杂度,导出程序基本路径集中的独立路径条数,这是确定程序中每个可执行语句至少执行一次所必须的测试用例数目的上界。

3.1.3导出基本路径集,确定程序的独立路径。

3.1.4根据③中的独立路径,设计测试用例的输入数据和预期输出。

域测试是一种基于程序结构的测试方法,基于对程序输入空间(域)的分析,选择测试点进行测试。主要为:

4.1域错误:程序的控制流存在错误,对于某一特定的输入可能执行的是一条错误路径,这种错误称为路径错误,也叫做域错误;

4.2 计算型错误:对于特定输入执行的路径正确,但赋值语句的错误导致输出结果错误,称为计算型错误;

4.3丢失路径错误:由于程序中的某处少了一个判定谓词而引起的丢失路径错误

符号测试基本思想是允许程序的输入不仅仅是具体的数值数据,而且包括符号值,符号值可以是基本的符号变量值,也可以是符号变量值的表达式

5.1符号测试执行的是代数运算,可以作为普通测试的一个扩充;

5.2符号测试可以看作是程序测试和程序验证的一个折衷办法;

5.3 符号测试程序中仅有有限的几条执行路径;

分析程序中的路径是指检验程序从入口开始,执行过程中经历的各个语句,直到出口。

Z路径覆盖对循环机制进行简化,减少路径的数量,使得覆盖所有路径成为可能,简化循环意义下的路径覆盖称为Z路径覆盖;

循环简化:限制循环次数,只考虑循环一次或零次情况;

循环简化的目的是限制循环的次数,无论循环的形式和循环体实际执行的次数,简化后的循环测试只考虑执行循环体一次和零次(不执行)两种情况,即考虑执行时进入循环体

一次和跳过循环体这两种情况。

程序变异是一种错误驱动测试。错误驱动测试是指该方法是针对某类特定程序错误的,要想找出程序中所有的错误几乎是不可能的,解决办法是将错误的搜索范围尽可能地缩小,

以利于专门测试某类错误是否存在。

1、定义:数据驱动测试或者基于规格说明的测试

只检查程序功能是否按照规格说明书规定正常使用,是否能接收数据及产生正确的输出

信息,并且满足数据库或者外部信息的完整性

①、是否有不正确或者遗漏的功能

③、接口上,输入输出是否正确

④、是否有数据结构错误或者外部数据库访问错误

⑥、初始化或者终止性错误

①、最大程度满足用户需求

②、相同动作可重复执行,枯燥部分可由机器完成

③、根据测试用例针对性的寻找问题,定位更准确,容易生成测试数据

④、测试直接和程序/系统要完成的操作相关联

②、如果规格设计错误,很难发现

④、结果取决于测试用例的设计

注意点:确定测试的优先级和测试重点,提高覆盖率,边界值分析必须使用

①、首先进行等价类划分,包括输入和输出条件,减少工作量提高效率

②、边界值分析,发现错误的能力最强

③、错误推断法,补充用例(这个凭经验)

④、对照需求和业务场景逻辑,检查用例

⑤、如果需求说明含有输入条件,设计开始就用到因果图和判定表驱动法

⑥、参数配置类的软件,要用正交实验法

⑦、功能图法,不同时期条件的有效性来设计数据

⑧、业务流清晰的系统,采用场景法

①、将所有可能输入数据(有效和无效)划分为若干个等价类,选取代表性的数据当做 测试用例,保证完整性和代表性

有效等价类:合理的有效的输入集合

无效等价类:无效的没有意义的输入集合,检查程序异常

按照区间、数值、集合、限制条件、处理方式划分

对输入或输出的边界值进行设计(5/7原则)

简化逻辑关系,操作步骤较复杂

针对不同存在条件、动作关系或者因果关系的设计用例方法

4大组成部分:条件桩,条件项;动作桩,动作项

事件触发的情景生成场景(同一件事不同触发顺序和处理结果形成事件流)

用功能图(流程图)形象的表达操作流(状态迁移图+布尔函数组成)

需要依靠判定表因果图表示逻辑,是黑盒+白盒混合用例的设计方法

基于以往的经验和出现的错误,推测软件可能存在的缺陷和错误,针对性的设计用例

从大量数据中挑选适量的有代表性的,合理设计用例

1、根据需求和规格要求,明确产品要求的正确性

2、针对性的找问题,正确定位

3、根据需求重要性确定测试等级和重点,减少缺陷

4、接口处,输入是否能正确接收,输出是否正确

5、站在用户角度思考,测试

根据需求中关于功能和性能的要求设计,制定参考范围

一组由前提条件、输入、执行条件、预期结果等组成,以完成对某个特定需求或者目标测试的数据,体现测试方案、方法、技术和策略的文档

2、为什么要写测试用例

科学有效的对测试步骤进行组织规划,方便管理,记录

3、测试用例主要包含哪些内容

编号、日期、设计和测试人员、优先级、标题、目标、环境、输入数据/动作、预期结果

4、编写测试用例需要什么

软件需求设计说明书、软件模板

5、设计测试用例的注意事项

从高到低,独立性,与功能一一对应,根据需求设计,由有经验的人员设计

6、设计测试用例的原则

有模板,正确性,代表性,可判断性,重现性,详细准确清晰的步骤,符合规范

市场上的用例缺陷管理工具很多:蛰了列举几个:mantis、redmine、jira、bugzilla、禅道等

编写→评审(修改→再次评审)→使用→保存管理→维护/升级

目标的描述、环境、输入输出数据/动作、步骤、预期结果、备注等

一种验证行为,程序中每一项都需要验证

①、检查单元模块内部错误,为软件评审提供依据

②、测试模块内重要的路径,以程序设计说明书和测试数据为依据,以检查出错误

③、检查信息能否正确流入和流出单元

④、内部数据的完整性、数据形式相互关系的正确性,以及全局变量在单元中的处理和影响

⑤、数据在边界处能否正常工作

⑥、单元的运行能否满足特点的逻辑覆盖

⑦、错误处理机制是否有效

程序语法检查、程序逻辑检查、模块接口测试、局部数据结构测试、路径测试、边界条件测试、错误处理测试、代码书写规范检查

①.编译语言对程序进行检查

①.检查程序逻辑是否正确

②.程序中的循环语句上下项以及循环次数是否有问题

③.函数或子模块是否有自我调用问题

模块接口是模块内核模块外联系的关键部位;当模块通过外部调用时,数据必须正确流入,当模块结束问题的处理返回调用模块时,数据必须能正确流出

2.4局部数据结构测试

局部数据结构是为了保证临时存储在模块内的数据,模块错误根源往往是局部数据结构

①.局部数据结构测试最常见的积累错误

②.不适合或者不相容的类型说明

④.变量初始化或者缺省值有错

⑤.不正确的变量名或者不正确的截断

⑥.出现上溢、下溢或者地址异常

对模块中的重要的执行路径进行测试,路径错误主要由错误的计算,不正确的比较或者不正常的控制流导致

①.程序内有一个n次循环,这个n次循环应该是1~n,而不是0~n

②.由小于、小于等于、等于、大于、大于等于、不等于确定的比较值出错

③.出现上溢、下溢和地址异常问题

完善的模块设计要求能预见出错的条件,并设置适当的出错处理,以便在一旦程序出错时,能对出错程序重做安排,保证其逻辑上的正确性

2.8代码书写规范检查

①.模块设计程序框架流程图

②.代码书写规范,对齐方式

④.参数类型,数据长度,指针,数组长度 大小

⑤.输入输出参数和结果

单元测试是针对每个程序的单体调试,主要步分为程序语法检查和程序逻辑检查

定义:功能测试就是对产品的各功能进行验证,根据功能测试用例,逐项测试,检查产品是否达到用户要求的功能;只需要考虑它的功能点不需要考虑软件的内部结构及代码等

链接是web应用系统的一个很重要的特征,主要是用于页面之间切换跳转,指导用户去一些不知道地址的页面的主要手段,链接测试一般关注三点:

①.链接是否按照既定指示那样,确实链接到了该链接的界面

②.测试该链接所链接的页面是否真的存在

③.保证系统中没有单独存在的页面(即没有链接指向,只能通过正确的URL地址才能访问)

也可以理解为数据落地;当用户在web应用系统上向服务器提交信息时,就需要使用表单操作,比如,用户注册,登录,信息变更等等;这种情况下,我们必须测试提交信息的完整性,

以检验提交给服务器的数据的正确性,当然,这还涉及到一些常理性的逻辑,比如出生日期和职业、工作年限是否恰当,所在地省份城市区域间的匹配等,如果设定使用默认值,也需要测试。

作为测试,很多时候都要站在用户的角度去思考,大部分用户都是目的驱动的,当他访问一个网站或者web系统时,会很快的浏览系统,找不到满足自己需求的信息时,会很快离开,很少有

用户愿意花时间去熟悉系统的结构;导航测试,就是在不同的页面跳转之间,或者按钮,对话框,列表以及窗口等,通过考虑这些因素,去判断一个应用系统是否易于导航:是否直观?系统的

主要模块是否可以通过主页访问或者到达?站点是否需要站内地图或者搜索引擎等其他帮助?web系统导航的另外一个重点就是页面结构、导航、菜单、风格等是否一致,确保用户可以凭借

直觉或者简单的判断就可以找到自己想要的内容。

可以理解为UI测试,其中包括图片、动画、边框、颜色、字体、背景、按钮等等。

其中要考虑以下几个重点:

①.图片要有明确的用途,代表;图片尺寸尽量小,一般采用JPG或者GIF压缩

②.页面整体风格是否和系统的用途一致

③.背景颜色,字体,搭配是否合理

主要用来检测web系统提供信息的准确性、相关性,比如:商品的价格,文字描述;信息的准确性,是否有拼写错误;信息的相关性,比如很多网站的“相关文章列表,视频列表等”

也就是我们常说的用户体验。用户浏览时是否感觉舒适,整体风格等等一般做一个类似问卷调查的形式,来判定用户的反馈信息,最好有最终用户的参与

现在有很多的操作系统,比如Windows、Unix、Linux、macintosh等;用户使用哪个系统取决于用户,因此,系统兼容测试就很有必要。

浏览器是web客户端最核心的组件,不同的浏览器,对Java,JavaScript,css或者HTML的规格都有不同的支持;另外,采用的框架和结构风格在不同浏览器中也存在不同的

显示甚至不显示,不同的浏览器对安全性的设置也是不同的。

测试浏览器兼容,有个方法就是创建一个兼容性矩阵,来测试不同厂商不同版本的浏览器兼容。

比如测试IE浏览器,可以通过一个叫做IEtester的工具来测试兼容,或者可以通过F12控制台来切换浏览器版本来测试兼容以前一些前端元素的显示等

安全测试的主要区域有以下几点:

3.1用户名和密码的有效无效性,注意大小写敏感,次数限制,是否可以不登录而浏览某些页面等

3.3测试用户操作时相关信息是否写入了日志文件、是否可追踪等

3.4如果使用了安全套字,需要测试加密是否正确,加密前后的信息完整性,正确性

3.5没有经过授权,是否可以在服务器端或者前端放置和编辑脚本的问题

4.1验证输入输出信息的一致性

4.2输入框前面的文字提示是否正确

4.3对特殊字符的处理、识别:单双引号,括号,逗号、分号等等,以及大小写状态,半角全角状态下的情况

4.4输入框的大小、长度、边框等

4.5不同字符的输入,以及字符组合情况的处理(数字+字母+字符等)

4.6对空格、tab换行键的处理机制

4.7密码输入框字符星号或者其他星号的转行,加密

4.8输入框输入字符长度是否有限制

4.9字符本身显示的颜色,规格等

4.10有些输入框需要加以限制,如输错,是否有提示?提示是否简单合理?

4.11输入状态,某种情况下输入框出于不可编辑,当再次处于编辑状态,输入框的输入状态是否有变化

4.12输入类型:是否允许复制黏贴剪切等输入操作

4.13关键字是否支持通配符,以及关键字的搜索能力,敏感字等情况

4.14输入框输入空格的情况

4.15比如登陆注册,各项输入条件的判定:是否输入,输入是否正确等

用户权限,就是该账号拥有哪些执行操作的权利

5.1给某账号赋予权限后,登陆该账号,查看是否拥有已赋予的权限,以及权限设置是否正确(权限是否超过或者不足)

5.2删除或修改已经登陆并且正在执行操作的账号权限,程序能否正确处理,验证

5.3重新注册系统变更登陆身份后再登陆,程序能否正确执行,之前所拥有的权限能否继续使用

5.4在用工作分配或者角色管理情况下,删除包含用户的工作组或者角色,程序能否正确处理

5.5不同权限账号登陆同一个系统,权限范围是否正确

5.6能否给信息为空、长用户名的账号添加权限

5.7是否允许删除系统管理员或者修改管理员权限?删除或者修改后的实际情况

5.8已登录的用户能否修改或者删除自己或者他人的权限,信息

5.9添加用户(有编号或者标识),不同用户名标识的组合情况下,权限能否处理正确

5.10修改用户权限或者信息后,对其他模块是否有影响

5.11如果修改用户信息和已存在的其他用户信息相同,能否修改成功?是否有对应提示

5.12修改某些设置,是否会对与该账号权限相同或者高于/低于该账号的其他账号的权限造成影响

5.13同一用户是否可以同时属于其他组,各个组的权限能否交叉

WEB端功能测试链接:

①.软件权限:其中包括发送信息,拨打电话,链接网络,访问手机信息,联系人信息等

②.数据在本地的存储、传输等

③.执行某些操作时导致的输入有效性验证、授权、数据加密等方面

④.基于各种通信协议或者行业标准来检查

①.验证app能否正确安装运行卸载,以及操作过程和操作前后对系统资源的占有情况

②.安装运行卸载的提示,报告等

③.检查安装路径,文件是否合理,组件是否正确注册等

①.用户界面(菜单、对话框、窗口)等布局,风格是否满足用户需求,文字位置,描述是否正确,界面美观程度,文字图片组合是否合理

②.用户友好性、人性化、便于操作等

①.评审需求,多方面考虑,整理出内在外在以及非功能性的直接间接功能点,对比需求,提取测试点

②.根据常用的一些分析方法,等价类边界值判定表因果图场景法等方法,设计测试用例,对提取的功能点进行覆盖

③.测试各个阶段不断跟踪缺陷,做好用例的更新迭代和不断变更需求所带来的业务或者需求的错误

①.极限测试:各种边界情况下验证app的响应能力

如:低电量、储存满。弱网等情况

②.响应能力测试:验证各种情况下不同操作能否满足用户响应需求

③.压力测试:反复长期操作下,系统该资源的使用情况

比如:前后台运行时来电话,短信,下载文件,听音乐看电影等不同情况下的表现

①.不同网络环境(WiFi、2G、3G、4G等)

②.各种设备品牌机型系统版本等兼容:苹果、安卓(不同品牌,不同安卓系统版本)等

bug修复后的回归测试,上线交付前进行全部的回归,验证

每次app版本迭代更新时,配合不同网络环境,及不同更新权限(强制更新,不强制更新),进行下载、安装、更新、启动运行等测试

①.支付结果的确认,数据库查询

金额足够、金额不足、重复支付、无网支付、弱网支付、同账号多平台一起支付、余额宝微信信用卡多种支付方式、不同支付方式的组合、密码正确/错误、支付上限等情况

App端功能测试链接:

也称为组装测试,联合测试,主要针对软件高层设计进行测试,一般以模块和子系统为单位进行测试

①.模块内集成,主要测试各个接口的交互

②.子系统内集成,子系统内各个模块的交互

③.系统集成,测试系统内各个子系统和模块的交互关系

不仅仅代码编译通过就算集成,而是所有模块子系统能正常运转,一般采用的方法是数据驱动,集成测试不看系统表象,而是对数据流进行分析,可分为自顶向下、自下向上、核心集成、分层集成等方法

4、集成测试方法和步骤

①.确定子系统的模块组成,保证这些模块都已通过单元测试

②.由开发组装这么模块,生成子系统,保证模块内功能尽可能发挥出来

③.设计测试用例,以一个关键模块为核心展开,围绕功能和性能,测试接口

④.搭建测试环境,按照用例进行测试

⑤.记录测试结果,总结问题

定义:检查系统是否能完成需求说明的内容,对系统能正常、完整的运行;其中包括软件、硬件和相关联的设备、测试数据

目的:模拟真实系统工作环境下通过与系统需求作比较,检验完整的软件配置项能否和系统正确连接,发现软件与系统/子系统之间与需求设计文档不符合或矛盾的地方

目标:功能是否达到规格说明书要求,是否存在其他缺陷,是否有完善到缺陷记录及跟踪等

4、系统测试的测试类型

多任务测试:同一时间内运行多个应用程序

临界测试:系统临界和应用系统临界

中断测试:软件在工作过程中被其他任务或意外事件终止当前正在进行的程序

之前已介绍过,此处略过

①.响应时间的性能测试

1、验收测试的首要条件

①.软件开发已完成,并且已修复已知缺陷

②.验收测试计划已被批准

③.对软件需求说明文档审查已完成

④.所有关键模块的代码审查已完成

①.验收系统是否按照需求文档开发,用户体验是否达到用户要求,与设计要求差距大小,完成的功能水平

②.验收系统是否达到了双方共识

③.验收系统的可靠性和维护性

④.验收系统的业务运行处理能力

①.验收人员要熟悉软件的功能和性能要求、软硬件环境要求,以及质量和验收要求

②.要有相应的验收要求文档,规格要求

③.根据验收要求进行验收测试,结果要出具报告,就行评审

4、验收测试的主要内容

①.软件是否满足需求文档规定的所有功能和性能的要求

②.文档资料等是否完整?

③.对功能测试、集成测试、系统测试、性能测试、安全测试等用例进行回归

①.审查提供验收的各类文档的正确性、完整性和统一性

②.审查项目功能是否达到设计需求说明书规定的要求

③.审查项目有关指标是否达到要求

⑤.对项目技术等水平做评估,得出项目的验收报告

在软件开发的各个阶段,都可能进行若干次回归测试,其在整个测试过程中占很大比重

只要软件发生修改,那么久需要重新测试,以确定修改的软件功能是否达到了预期目的,以及修改可能产生的新的问题(已修改部分对原功能产生影响)

确认软件经过修改或变更后是否仍满足所有的需求

回归测试是重复测试,要求使用相同的方法、测试用例和数据,在相同的环境下测试

①.测试所有修改或修正过的功能模块

②.测试与被修改模块相关的模块

③.测试所有新增加的模块

每次有改动或者需求迭代变更时候

验证新功能,保证旧功能不被影响

测试验证被测软件在不同软件和硬件条件中运行的情况,覆盖各种软件、硬件环境,其实质就是测试软件是否与其他与之交互元素之间的兼容(比如浏览器、操作系统、硬件)

2、为什么要做配置测试

测试软件的容错性、发现隐藏的bug,以及其对产品的影响,得到最佳的配置

①.不同主机的配置测试

②.不同组件的配置测试

③.不同外设的配置测试

④.不同接口的配置测试

①.不同操作系统平台兼容性测试

②.同一操作系统不同版本兼容性测试

③.软件本身向前向后兼容测试

④.软件本身与其他软件兼容测试

}

软件测试(源于课件的整理,进行完善)。

目录:/ /被测程序,检查执行结果与预期结果的差异,分析执行效率和健壮性等性能

测试方法:编写测试用例-运行测试结果-分析输出结果

动态测试功能测试\数据驱动测试、功能测试/数据驱动测试在已知产品支持的功能前提下,通过测试检测各功能能否正常使用。

测试方法:等价类、边值分析、因果图、基于判定表的测试、正交测试、场景测试等

结构测试/逻辑驱动测试,在知道产品内部工作过程的基础上,通过测试可以检测产品内部工作是否按规格书规定正常进行。

测试方法:语句覆盖、判定覆盖、条件覆盖、路径覆盖、条件组合覆盖

/的粒度最小,一般由开发团队采用白盒方式测试,主要测试单元是否符合黑盒测试

/在单元测试和系统测试之间起到“桥梁作用”,一般由开发团队采用白盒和黑盒的方式进行测试。白盒测试

/粒度最大,一般由独立测试小组采用黑匣子方式测试,主要测试系统是否符合《/》。

单元测试与系统测试类似,但主要区别在于测试人员不同,验收测试由用户执行。

集成测试主要用于测试模块和模块之间的接口,还测试主要的业务功能。

系统测试是在经过上述每个阶段的测试确认后,将系统完全模拟到客户环境中进行的测试。

具体方法(白盒具体方法的定义)语句的覆盖)选择足够的测试用例,使得“设计”的各集成测试能够执行至少一次。

判定覆盖:执行足够的测试用例,以使既验证“设计”,又验证“需求”的每个系统测试 至少获得一次“真”和“假”值。

条件覆盖:运行充分的测试用例,以获得需求规格说明书”的各验收测试可能的各种结果。

盖: 执行足够测试用例,使判定中的每个条件取到各种可能的值,并使得判定取得各种可能的结果。

条件组合覆盖:执行足够的测试用例,使得每个判定中的各种可能条件的组合都至少出现一次。

1)选择逻辑覆盖标准。
2)按照覆盖标准列出所有情况。
3)选择确定测试用例。

4)验证分析运行结果与预期结果。

用白盒测试以下程序段:

1.语句覆盖:使得程序中的每个语句至少被执行一次。

满足语句覆盖的情况: 执行路径 - ace

2.判定覆盖:每个判定至少为“真”或“假”各一次。

3.条件覆盖:判定中的每个条件获得各种可能。

4. 判定\条件覆盖:同时满足条件和判定覆盖。

5. 条件组合覆盖:使得判定中条件的各种可能的组合都至少出现一次。

等价分类法、边值分析法、错误推测法、因果图法

等价分类法:根据程序的I/O特性,将程序的定义域划分为有限个等价区域-“等价类”,从等价类中选择具有:“代表性”的用例。可分为有效等价类和无效等价类(没意义的输入数据构成的集合)。

边值分析法:选择的等价类的边缘值作为测试用例,让每个等价类的边界都得到测试,选择测试用例既要考虑到“input”也要考虑到“output”。

边界原则:A.输入/输出值范围/边界;B.输入/输出值的个数;C.输入输出有续集的边界。

错误推测法:凭经验或者直觉推测出可能发生的错误,列出程序种可能有的错误和容易发生错误的特殊情况,选择测试用例。

因果图法:将输入条件作为“因”,输出条件作为“果”,将黑盒看成从因到果的网络图,采用逻辑图的形式来表达功能说明书中输入条件的各种组合与输出的关系。根据这种关系可选择高效的测试用例。

所有测试过程都应采用综合测试策略;即先作静态分析,再作动态测试。并事先制订测试计划。测试步骤如图:

    I/O参数值的个数、类型、次序、格式是否正确,I/O文件属性、操作是否正确

    边界条件常闭噢扩 循环边界,最大小值、控制流中的等于、大于、小于等。

    数据说明是否正确、一致,变量以及初始值定义是否正确。

驱动模块:模拟主程序功能,用于向别测试程序传递数据,接收、打印从被测试程序返回的数据。

桩模块:用于模拟由被测试模块所调用的下属模块功能。

重点测试模块的接口部分,需要设计驱动模块和桩模块。

确定模块组装方案,将经过测试的某块组装成一个完整的系统,分为渐增式和非渐增式。

渐增式 分为自顶向下 和自底向上,(又分别包括深度优先和广度优先)

优点:能够尽早发现系统主控方面的问题。

缺点:无法验证桩模块是否完全模拟了下属模块的功能。

优点:驱动模块较容易编写桩模块,能够尽早查出底层涉及较复杂的算法和实际的I/O模块中的错误。

缺点:最后才能发现系统主控方面的问题。

验证系统的功能性能等特性是否符合需求规格说明。

制定测试计划,运用黑盒法,验证软件特性是否与需求符合

软件配置— 指软件工程过程中所产生的所有信息项:文档、报告、程序、表格、数据。随着软件工程过程的进展软件配置项(SCI  software Configuration Item)快速增加和变化。应复查SCI是否齐全

α测试:是在开发机构的监督下,由个别用户在确认测试阶段后期对软件进行测试,目的是评价软件的FLURPS(功能、局域化、可使用性、可靠性、性能和支持),注重界面和特色。

β测试:由支持软件预发行的客户对FLURPS进行测试,主要目的是测试系统的可支持性。

将经过确认测试的软件,与计算机硬件、外设、支持软件等一起,在实际运行环境下测试

验收测试是以用户为主的测试。

P.s.最近在看《Google 软件测试之道》,受益良多,希望有时间能多看几次。

}

1. 单元测试入门——优秀基因

单元测试最初兴起于敏捷社区。1997年,设计模式四巨头之一Erich Gamma和极限编程发明人Kent Beck共同开发了JUnit,而JUnit框架在此之后又引领了xUnit家族的发展,深刻的影响着单元测试在各种编程语言中的普及。当前,单元测试也成了敏捷开发流行以来的现代软件开发中必不可少的工具之一。同时,越来越多的互联网行业推崇自动化测试的概念,作为自动化测试的重要组成部分,单元测试是一种经济合理的回归测试手段,在当前敏捷开发的迭代(Sprint)中非常流行和需要。

然而有些时候,这些单元测试并没有有效的改善生产力,甚至单元测试有时候变成一种负担。人们盲目的追求测试覆盖率,往往却忽视了测试代码本身的质量,各种无效的单元测试反而带来了沉重的维护负担。

本篇讲义将会集中的从单元测试的入门、优秀单元测试的编写以及单元测试的实践等三个方面展开探讨。

文中的示例代码块均使用Java语言。
文中的粗体部分表示重点内容和重点提示。
文中的引用框部分,一般是定义或者来源于其它地方。
文中标题的【探讨】,表示此部分讲师与学员共同探讨并由讲师引导,得到方案。
文中的代码变量和说明用方框圈起来的,是相关代码的变量、方法、异常等。

1.1 单元测试的价值

  • 在维基百科中,单元测试被定义为一段代码调用另一段代码,随后检验一些假设的正确性。

    以上是对单元测试的传统定义,尽管从技术上说是正确的,但是它很难使我们成为更加优秀的程序员。这些定义在诸多讨论单元测试的书籍和网站上,我们总能看到,可能你已经厌倦,觉得是老生常谈。不过不必担心,正是从这个我们熟悉的,共同的出发点,我们引申出单元测试的概念。

    或许很多人将软件测试行为与单元测试的概念混淆为一谈。在正式开始考虑单元测试的定义之前,请先思考下面的问题,回顾以前遇到的或者所写的测试:

    • 两周或者两个月、甚至半年、一年、两年前写的单元测试,现在还可以运行并得到结果么?
    • 两个月前写的单元测试,任何一个团队成员都可以运行并且得到结果么?
    • 是否可以在数分钟以内跑完所有的单元测试呢?
    • 可以通过单击一个按钮就能运行所写的单元测试么?
    • 能否在数分钟内写一个基本的单元测试呢?

    当我们能够对上述的问题,全部回答“是”的时候,我们便可以定义单元测试的概念了。优秀的测试应该以其本来的、非手工的形式轻松执行。同时,这样的测试应该是任何人都可以使用,任何人都可以运行的。在这个前提下,测试的运行应该能够足够快,运行起来不费力、不费事、不费时,并且即便写新的测试,也应该能够顺利、不耗时的完成。如上便是我们需要的单元测试。

    涵盖上面描述的要求的情况下,我们可以提出比较彻底的单元测试的定义:

    Test),是一段自动化的代码,用来调动被测试的方法,而后验证基于该方法或类的逻辑行为的一些假设。单元测试几乎总是用单元测试框架来写的。它写起来很顺手,运行起来不费时。它是全自动的、可信赖的、可读性强的和可维护的。

    接下来我们首先讨论单元测试框架的概念:

    框架是一个应用程序的半成品。框架提供了一个可复用的公共结构,程序员可以在多个应用程序之间进行共享该结构,并且可以加以扩展以便满足它们的特定的要求。

    单元测试检查一个独立工作单元的行为,在Java程序中,一个独立工作单元经常是一个独立的方法,同时就是一项单一的任务,不直接依赖于其它任何任务的完成。

    所有的代码都需要测试。于是在代码中的满足上述定义,并且对独立的工作单元进行测试的行为,就是我们讨论的单元测试。

  • 单元测试是非常有威力的魔法,但是如果使用不当也会浪费你大量的时间,从而对项目造成巨大的不利影响。另一方面,如果没有恰当的编写和实现单元测试,在维护和调用这些测试上面,也会很容易的浪费很多时间,从而影响产品代码和整个项目。

    我们不能让这种情况出现。请切记,做单元测试的首要原因是为了工作更加轻松。现在我们一起探讨下如何编写优秀的单元测试,只有如此,方可正确的开展单元测试,提升项目的生产力。

    根据上一小节的内容,首先我们列出一些优秀的单元测试大多具备的特点:

    1. 自动的、可重复的执行的测试
    2. 开发人员比较容易实现编写的测试
    3. 一旦写好,将来任何时间都依旧可以用
    4. 团队的任何人都可运行的测试
    5. 一般情况下单击一个按钮就可以运行
    6. 测试可以可以快速的运行
  • 或许还有更多的情形,我们可以再接再厉的思考出更多的场景。总结这些,我们可以得到一些基本的应该遵循的简单原则,它们能够让不好的单元测试远离你的项目。这个原则定义了一个优秀的测试应该具备的品质,合称为A-TRIP

    接下来,我们分别就每一个标准进行分析和解释,从而我们可以正确的理解这些。

    • 单元测试需要能够自动的运行。这里包含了两个层面:调用测试的自动化以及结果检查的自动化。

      1. 调用测试的自动化:代码首先需要能够正确的被调用,并且所有的测试可以有选择的依次执行。在一些时候,我们选择IDE(Integration Development Environment,集成开发环境)可以帮助我们自动的运行我们指定的测试,当然也可以考虑CI(Continuous Integration,持续集成)的方式进行自动化执行测试。
      2. 结果检查的自动化:测试结果必须在测试的执行以后,“自己”告诉“自己”并展示出来。如果一个项目需要通过雇佣一个人来读取测试的输出,然后验证代码是否能够正常的工作,那么这是一种可能导致项目失败的做法。而且一致性回归的一个重要特征就是能够让测试自己检查自身是否通过了验证,人类对这些重复性的手工行为也是非常不擅长。
    • 好的单元测试应该是彻底的,它们测试了所有可能会出现问题的情况。一个极端是每行代码、代码可能每一个分支、每一个可能抛出的异常等等,都作为测试对象。另一个极端是仅仅测试最可能的情形——边界条件、残缺和畸形的数据等等。事实上这是一个项目层面的决策问题。

      另外请注意:Bug往往集中的出现在代码的某块区域中,而不是均匀的分布在代码的每块区域中的。对于这种现象,业内引出了一个著名的战斗口号“不要修修补补,完全重写!”。一般情况下,完全抛弃一块Bug很多的代码块,并进行重写会令开销更小,痛苦更少。

      总之,单元测试越多,代码问题越少。

    • 每一个测试必须可以重复的,多次执行,并且结果只能有一个。这样说明,测试的目标只有一个,就是测试应该能够以任意的的顺序一次又一次的执行,并且产生相同的结果。意味着,测试不能依赖不受控制的任何外部因素。这个话题引出了“测试替身”的概念,必要的时候,需要用测试替身来隔离所有的外界因素。

      如果每次测试执行不能产生相同的结果,那么真相只有一个:代码中有真正的Bug。

    • 测试应该是简洁而且精炼的,这意味着每个测试都应该有强的针对性,并且独立于其它测试和环境。请记住,这些测试,可能在同一时间点,被多个开发人员运行。那么在编写测试的时候,确保一次只测试了一样东西。

      独立的,意味着你可以在任何时间以任何顺序运行任何测试。每一个测试都应该是一个孤岛。

    • 测试代码需要是专业的。意味着,在多次编写测试的时候,需要注意抽取相同的代码逻辑,进行封装设计。这样的做法是可行的,而且需要得到鼓励。

      测试代码,是真实的代码。在必要的时候,需要创建一个框架进行测试。测试的代码应该和产品的代码量大体相当。所以测试代码需要保持专业,有良好的设计。

  • 这里我们讨论生产力的问题。

    当单元测试越来越多的时候,团队的测试覆盖率会快速的提高,不用再花费时间修复过去的错误,待修复缺陷的总数在下降。测试开始清晰可见的影响团队工作的质量。但是当测试覆盖率不断提高的时候,我们是否要追求100%的测试覆盖率呢?

    事实上,那些确实的测试,不会给团队带来更多价值,花费更多精力来编写测试不会带来额外的收益。很多测试未覆盖到的代码,在项目中事实上也没有用到。何必测试那些空的方法呢?同时,100%的覆盖率并不能确保没有缺陷——它只能保证你所有的代码都执行了,不论程序的行为是否满足要求,与其追求代码覆盖率,不如将重点关注在确保写出有意义的测试。

    当团队已经达到稳定水平——曲线的平坦部分显示出额外投资的收益递减。测试越多,额外测试的价值越少。第一个测试最有可能是针对代码最重要的区域,因此带来高价值与高风险。当我们为几乎所有事情编写测试后,那些仍然没有测试覆盖的地方,很可能是最不重要和最不可能破坏的。

    接下来分析一个测试因素影响的图:

    事实上,大多数代码将测试作为质量工具,沿着曲线停滞了。从这里看,我们需要找出影响程序员生产力的因素。本质上,测试代码的重复和多余的复杂性会降低生产力,抵消测试带来的正面影响。最直接的两个影响生产力的因素:反馈环长度调试。这两者是在键盘上消耗程序员时间的罪魁祸首。如果在错误发生后迅速学习,那么花在调试上的时间是可以大幅避免的返工——同时,反馈环越长,花在调试上的时间越多。

    等待对变更进行确认和验证,在很大程度上牵扯到测试执行的速度,这个是上述强调的反馈环长度和调试时间的根本原因之一。另外三个根本原因会影响程序员的调试量。

    1. 测试的可读性:缺乏可读性自然降低分析的熟读,并且鼓励程序员打开调试器,因为阅读代码不会让你明白。同时因为很难看出错误的所在,还会引入更多的缺陷。
    2. 测试结果的准确度:准确度是一个基本要求。
    3. 可依赖性和可靠性:可靠并且重复的方式运行测试,提供结果是另一个基本要求。
  • 假设先写了最重要的测试——针对最常见和基本的场景,以及软件架构中的关键部位。那么测试质量很高,我们可以讲重复的代码都重构掉,并且保持测试精益和可维护。那么我们想象一下,积累了如此高的测试覆盖率以后,唯一没测试到的地方,只能是那些最不重要和最不可能破坏的,项目没有运行到的地方了。平心而论,那么地方也是没有什么价值的地方,那么,之前的做法倾向于收益递减——已经不能再从编写测试这样的事情中获取价值了。

    这是由于不做的事情而造成的质量稳态。之所以这么说,是因为想要到达更高的生产力,我们需要换个思路去考虑测试。为了找回丢掉的潜力,我们需要从编写测试中找到完全不同的价值——价值来自于创新及设计导向,而并非防止回归缺陷的保护及验证导向。

    总而言之,为了充分和完全的发挥测试的潜力,我们需要:

    1. 像生产代码一样对待你测试代码——大胆重构、创建和维护高质量测试
    2. 开始将测试作为一种设计工具,指导代码针对实际用途进行设计。

    第一种方法,是我们在这篇讲义中讨论的重点。多数程序员在编写测试的时候会不知所措,无法顾及高质量,或者降低编写、维护、运行测试的成本。

    第二种方法,是讨论利用测试作为设计的方面,我们的目的是对这种动态和工作方式有个全面的了解,在接下来的[探讨]中我们继续分析这个话题。

1.2 [探讨]正确地认识单元测试

  • 练习:一个简单的单元测试示例

    我们从一个简单的例子开始设计测试,它是一个独立的方法,用来查找list中的最大值。

    比如,给定一个数组 { 1, 50, 81, 100 },这个方法应该返回100,这样就构成了一个很合理测试。那么,我们还能想出一些别的测试么?就这样的方法,在继续阅读之前,请认真的思考一分钟,记下来所有能想到的测试。

    在继续阅读之前,请静静的思考一会儿……

    想到了多少测试呢?请将想到的测试都在纸上写出来。格式如下:

然后我们编写一个基本的符合要求的函数,来继续进行测试。

然后请考虑上述代码是否有问题,可以用什么样的例子来进行测试。

  • 分析:为什么不写单元测试

    请思考当前在组织或者项目中,如何写单元测试,是否有不写单元测试的习惯和借口,这些分别是什么?

  • 分析:单元测试的结构与内容

    当我们确定要写单元测试的时候,请认真分析,一个单元测试包含什么样的内容,为什么?

  • 分析:单元测试的必要性

    请分析单元测试必要性,尝试得出单元测试所带来的好处。

    单元测试的主要目的,就是验证应用程序是否可以按照预期的方式正常运行,以及尽早的发现错误。尽管功能测试也可以做到这一点,但是单元测试更加强大,并且用户更加丰富,它能做的不仅仅是验证应用程序的正常运行,单元测试还可以做到更多。

    • 功能测试大约可以覆盖到70%的应用程序代码,如果希望进行的更加深入一点,提供更高的测试覆盖率,那么我们需要编写单元测试了。单元测试可以很容易的模拟错误条件,这一点在功能测试中却很难办到,有些情况下甚至是不可能办到的。单元测试不仅提供了测试,还提供了更多的其它用途,在最后一部分我们将会继续介绍。

    • 在一个项目中,经过单元测试通过的代码,可以称为高质量的代码。这些代码无需等待到其它所有的组件都完成以后再提交,而是可以随时提交,提高的团队的效率。如果不进行单元测试,那么测试行为大多数要等到所有的组件都完成以后,整个应用程序可以运行以后,才能进行,严重影响了团队效率。

    • 在没有进行单元测试的代码中,重构是有着巨大风险的行为。因为你总是可能会损坏一些东西。而单元测试提供了一个安全网,可以为重构的行为提供信心。同时在良好的单元测试基础上,对代码进行改进实现,对一些修改代码,增加新的特性或者功能的行为,有单元测试作为保障,可以防止在改进的基础上,引入新的Bug。

    • 在一些代码的文档中,示例的威力是众所周知的。当完成一个生产代码的时候,往往要生成或者编写对应的API文档。而如果在这些代码中进行了完整的单元测试,则这些单元测试就是最好的实例。它们展示了如何使用这些API,也正是因为如此,它们就是完美的开发者文档,同时因为单元测试必须与工作代码保持同步,所以比起其它形式的文档,单元测试必须始终是最新的,最有效的。

JUnit诞生于1997年,Erich Gamma 和 Kent Beck 针对 Java 创建了一个简单但是有效的单元测试框架,随后迅速的成为 Java 中开发单元测试的事实上的标准框架,被称为 xUnit 的相关测试框架,正在逐渐成为任何语言的标准框架。

以我们的角度,JUnit用来“确保方法接受预期范围内的输入,并且为每一次测试输入返回预期的值”。在这一节里,我们从零开始介绍如何为一个简单的类创建单元测试。我们首先编写一个测试,以及运行该测试的最小框架,以便能够理解单元测试是如何处理的。然后我们在通过 JUnit 展示正确的工具可以如何使生活变得更加简单。

本文中使用 JUnit 4 最新版进行单元测试的示例与讲解。

  • 这里我们开始构建单元测试。

    首先我们使用之前一节的【探讨】中使用过的类,作为被测试的对象。创建一个类,叫做HelloWorld,该类中有一个方法,可以从输入的一个整型数组中,找到最大的值,并且返回该值。

    虽然我们针对该类,没有列出文档,但是 HelloWorld 中的 int getLargestElement(int[])方法的意图显然是接受一个整型的数组,并且以 int 的类型,返回该数组中最大的值。编译器能够告诉我们,它通过了编译,但是我们也应该确保它在运行期间可以正常的工作。

    单元测试的核心原则是“任何没有经过自动测试的程序功能都可以当做它不存在”。getLargestElement 方法代表了 HelloWorld 类的一个核心功能,我们拥有了一些实现该功能的代码,现在缺少的只是一个证明实现能够正常工作的自动测试。

    这个时候,进行任何测试看起来都会有些困难,毕竟我们甚至没有可以输入一个数组的值的用户界面。除非我们使用在【探讨】中使用的类进行测试。

    获取最大值正确,通过测试。
    

    第一个 HelloWorldTest 类非常简单。它创建了 HelloWorld 的一个实例,传递给它一个数组,并且检查运行的结果。如果运行结果与我们预期的不一致,那么我们就在标准输出设备上输出一条消息。

    现在我们编译并且运行这个程序,那么测试将会正常通过,同时一切看上去都非常顺利。可是事实上并非都是如此圆满,如果我们修改部分测试,再次运行,可能会遇到不通过测试的情况,甚至代码异常。

    接下来我们修改代码如下:

    当我们再次执行代码的时候,代码运行就会报错。运行结果如下:

    按照第一节中的描述的优秀的单元测试,上述代码毫无疑问,称不上优秀的单元测试,因为测试连运行都无法运行。令人高兴的是,JUnit 团队解决了上述麻烦。JUnit 框架支持自我检测,并逐个报告每个测试的所有错误和结果。接下来我们来进一步了解 JUnit 。

    JUnit 是一个单元测试框架,在设计之初,JUnit 团队已经为框架定义了3个不相关的目标:

    • 框架必须帮助我们编写有用的测试
    • 框架必须帮助我们创建具有长久价值的测试
    • 框架必须帮助我们通过复用代码来降低编写测试的成本

    下载地址:,下载如下两个 JAR 包,放到项目的依赖的路径中。

    在 IDEA 的项目中,添加一个文件夹 lib,将上述两个文件添加到 lib 中。

    如上的操作,我们便定义了一个单元测试,使用 JUnit 编写了测试。主要的要点如下:

    1. 针对每个测试的对象类,单独编写测试类,测试方法,避免副作用
  • 创建一个测试方法的要求:该方法必须是公共的,不带任何参数,返回值类型为void,同时必须使用@Test注解
  • 为了进行验测试验证,我们使用了由 JUnit 的 Assert 类提供的 assert 方法。正如我们在上面的例子中使用的那样,我们在测试类中静态的导入这些方法,同时还有更多的方法以供我们使用,如下我们列出一些流行的 assert 方法。

    a == b,msg可选,用来解释失败的原因
    a != b,msg可选,用来解释失败的原因
    x 是真,msg可选,用来解释失败的原因
    x 是假,msg可选,用来解释失败的原因
    a 不是 b,msg可选,用来解释失败的原因
    x 是null,msg可选,用来解释失败的原因
    x 不是null,msg可选,用来解释失败的原因
    用匹配器进行断言,高级应用*,不再此文档讨论

    一般来说,一个测试方法包括了多个断言。当其中一个断言失败的时候,整个测试方法将会被终止——从而导致该方法中剩下的断言将会无法执行了。此时,不能有别的想法,只能先修复当前失败的断言,以此类推,不断地修复当前失败的断言,通过一个个测试,慢慢前行。

  • 到目前为止,我们只是介绍了断言本身,很显然我们不能只是简单的把断言方法写完,就希望测试可以运行起来。我们需要一个框架来辅助完成这些,那么我们就要做多一些工作了。很幸运的是,我们不用多做太多。

    如果在测试之前有些工作我们只想做一次,用不着每个函数之前都做一次。比如读一个很大的文件。那就用下面两个来标注:
    @BeforeClass: 测试类初始化的时候,执行的方法
    @AfterClass: 测试类销毁的时候,执行的方法

  • 如果我们暂时不用测试一个用例,我们不需要删除或都注释掉。只要改成:@Ignore ,你也可以说明一下原因@Ignore("something happens")
  • 示例代码:下面的代码代表了单元测试用例的基本框架

    //TODO: 测试预置条件,测试安装 //TODO: 测试清理,测试卸载

    单元测试框架的过程如下:

    JUnit 需要注意的事项:

    1. 每个 @Test 都是一个测试用例,一个类可以写多个 @Test
    2. @After / @Before 也可以是多个,并且有执行顺序。在每个 @Test 前后执行多次。
      • @Before 多个名字长度一致,z -> a, 长度不一致,会先执行名字短的。
    3. @AfterClass / @BeforeClass 也可以是多个,并且有执行顺序。只会在测试类的实例化前后各执行一次。
      • @AfterClass 多个名字长度一致,a -> z, 长度不一致,会后执行名字短的。
    4. 测试结果有 通过、不通过和错误 三种。
  • 这一小节,我们来介绍一下 JUnit 4 中的新的测试运行器(Test Runner)。如果我们刚开始编写测试,那么我们需要尽可能快捷的运行这些测试,这样我们才能够将测试融合到开发循环中去。

    编码 → 运行 → 测试 → 编码……

    其中,JUnit 就可以让我们构建和运行测试。我们可以按照组合测试Suite 以及参数化测试分别来运行测试。

    • 测试集 (Suite 或者 test suite)一组测试。测试集是一种把多个相关测试归入一组的便捷测试方式。可以在一个测试集中,定义需要打包测试的类,并一次性运行所有包含的测试;也可以分别定义多个测试集,然后在一个主测试集中运行多个相关的测试集,打包相关的测试的类,并一次性运行所有包含的测试。

    • 参数化测试(Parameterized)是测试运行器允许使用不同的参数多次运行同一个测试。参数化测试的代码如下:

      对于参数化测试的运行器来运行测试类,那么必须满足以下要求:

    • 必须声明测试中所使用的实例变量
  • 为测试指定构造方法,或者一个个全局变量的成员进行赋值
  • 所有的测试方法以@Test注解,实例化被测试的程序,同时在断言中使用我们提供的全局变量作为参数

1.4 [探讨]按业务价值导向进行单元测试设计

  • 练习:测试的结果是否正确

    如果测试代码能够运行正确,我们要怎么才能知道它是正确的呢?

    如何应对测试数据量比较大的时候,我们的测试代码如何编写?

  • 寻找边界条件是单元测试中最有价值的工作之一,一般来说Bug出现在边界上的概率比较大。那么我们都需要考虑什么样的边界条件呢?

  • 练习:强制产生错误条件

    关于产生错误的条件,请列出一个详细的清单来。

  • 分析:测试作为设计工具

    第一节【专题】中,我们有讨论设计潜力的曲线,其中第二条方案强调了测试作为设计的工具。那么我们想就两个方面来讨论这个测试设计的问题。

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...

  • 2. 单元测试进阶——寻求优秀 2.1 使用测试替身 在现代开发者测试的上下文中,除了允许在某些依赖缺失的情况下编...

  • 再过两个小时就要22岁了,其实是96年5月份的,认真算来21周岁还不到。人嘛,在这个时候总想显得自己更年轻一点。《...

  • 文@江寒园 在前几篇有关电影叙事结构的文章中稍稍提及过电影当中的“主题—并置”叙事,而“主题—并置”仅仅作为“并置...

  • 最近两周感觉孩子又开始反复了,说好周一到五不用手机,结果孩子说上下学路上别人都在玩手机,就他没手机,我们一软弱,他...

}

我要回帖

更多关于 单元测试的方法有哪些 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信