软件测试课程设计要求
1、 分组要求:
每组2人,班级内自由组合
2、 测试内容:
1) 系统需求测试及确认
2)白盒测试:
选择编写测试用例,并进行2种类型以上的覆盖测试,并针对测试用例画出表格
3)黑盒测试:
选择编写测试用例,针对模块中的功能点进行测试,测试用例选择不少于15个
4)自动化测试:(压力测试选作)
使用LoadRunner或qtp,对web应用程序进行性能测试,描述测试目的及测试结果
3、 课程设计报告编写内容:
1) 测试成员介绍(人员、负责内容)
2) 测试目标(所针对的web程序介绍,测试的项目内容介绍)
3) 测试计划(包含时间、目标及对应方法、检验标准)
4) 测试用例(格式要按照测试用例书写规范)
5) 自动化测试中的(要求有测试目的说明,测试过程截图)
6) 测试结果(描述与测试用例中的结果比对、功能的正确性)
7) 测试结论(对课程设计的总结)
报告内容不少于30页。
4、 时间安排:
7月6日—7月10日
要求提交:课程设计报告(打印稿、电子稿)、测试所用的系统程序源代码。
5、 评分标准:
课程设计报告书写内容,60%
答辩及过程演示,40%
目录
1、 系统需求分析及设计概述... 5
1.1系统需求与功能概述... 5
1.2 系统分析设计概述... 5
2、 测试计划书... 5
2.1基本内容... 5
2.2 任务概述... 5
2.3 计划... 6
3、测试用例... 6
4 测试结果分析... 6
4.1测试计划执行情况... 6
4.2 软件需求测试结论... 6
4.3 评价... 7
5、测试总结... 7
6.参考资料... 7
附件1 界面测试公共测试用例... 8
附件2 界面测试公共测试用例... 15
附件3 缺陷报告模板... 28
附件4 测试用例设计参考... 29
附件5 课程设计报告封面... 31
1、 系统需求分析及设计概述
1.1系统需求与功能概述
1.2 系统分析设计概述
2、 测试计划书
2.1基本内容
1、项目背景
【说明项目的来源、委托单位及主管部门。】
所开发软件名称:
项目委托单位:
项目开发单位:
软件用途:
2、定义
【列出测试计划中所用到的专门术语的定义和缩写词的原意。】
静态测试:主要方法有审阅,检查。
单元测试,组装测试,系统测试
主键:数据库表中与其他表主键关联的域。
3、参考资料
【列出有关资料的作者、标题、编号、发表日期、出版单位或资料来源,可包括:
a. 项目的计划任务书、合同或批文;
b. 项目开发计划;
c. 需求规格说明书;
d. 概要设计说明书;
e. 详细设计说明书;
f. 用户操作手册;
g. 本测试计划中引用的其他资料、采用的软件开发标准或规范。】
2.2 任务概述
1、目标
测试是“为了尽可能地发现软件中的错误,而不是为了证明程序的正确性”,测试的目的就是在软件投入生产性运行之前,按照测试的原则要求,尽可能多的发现软件中的错误。
2、运行环境
硬件要求:
运行环境:
2.3 计划
1、测试方案
【说明确定测试方法和选取测试用例的原则。】
测试方法:黑盒测试
选取测试用例的原则:
等价类划分
边界值分析
2、测试准备
1.确定代码运行环境
3、测试机构及人员
【测试机构名称、负责人和职责。】
负责人:
职责:
3、测试用例
【本章是报告核心之处,需要分功能模块对系统进行测试用例设计以及软件测试。建议大家从白盒测试开始(即测试业务层(使用JUnit进行单元测试),界面层测试)到最后的功能测试】
4 测试结果分析
4.1测试计划执行情况
1、测试项目
2、测试机构人员
3、测试结果
4.2 软件需求测试结论
【按顺序给出每一项需求测试的结论。包括:
a. 证实的软件能力;
b. 局限性(即项需求未得到充分测试的情况及原因)。】
如:测试中,所有的测试项目均能到达预期的效果,也就是说,基本上该系统已经能够正常的进行工作,实现基本资料维护模块,日常业务模块,查询统计模块,并能提供稳定的文档的导入及打印,基本上是实现了需求分析中该系统所应该实现的功能。
4.3 评价
1、软件能力
【经过测试所表明的软件能力。】
测试项目名称:商品库存管理系统
测试名称:0001 用户登录功能测试
测试内容:输入用户名和密码,例如:angel和345678
测试目的:测试是否能成功登陆该系统。
我们可以从以上六个测试的内容、目的和结果中,得出这个结论:该系统能够实现基本的信息的维护,日常业务,和查询统计功能。
2、缺陷和限制
【说明测试所揭露的软件缺陷和不足,以及可能给软件运行带来的影响。】
如局限性:由于MySQL的一些不明原因,GDK和UTF_8编码的选择不能被安装,所以只能选择标准状态下的英文编码,因此系统所有的数据均由数字和英文表示,在下次的改进版中将会加以改善.
3、建议
【提出为弥补上述缺陷的建议。】
4、测试结论
【说明能否通过。】
各项测试用例测试下来说明,该系统相对稳定,测试用例的选择能够适时地满足测试用例设计需求,基本上达到项目测试所应具有的水平,相对较客观完善,与预期效果相差无几,满足了用户的相应需求.
5、测试总结
6.参考资料
附件1 界面测试公共测试用例
界面测试一般包括页面文字,控件使用,少图,CSS,颜色等。
1.文字
内容一致性:
1)公司要求文字的一致性,例如各种宣传文字、注册的协议条款、版权信息等;
2)各处相同含义文字的一致性,例如标题栏文字、页面主题文字、弹出窗口文字、菜单名称、功能键文字等。
样式一致性
1)(通常分类包括)各类文字字体、字号、样式、颜色、文字间距、对齐方式;
2)按钮的文字间距,按钮长度一定前提下,2个字的按钮,需要中间空一格(或者其它约定,需要统一);
3)链接文字,同一类,菜单、小标题、页角文字链接,在点击时颜色变化要相同;
4)对齐方式,页面上文字的对齐,例如表单、菜单列、下拉列表中文字的对齐方式(左、右、居中等要统一)
语言习惯:
1)中文:文字简单,含义明确,无歧异,无重复,无别字,正确运用标点符号。
2)英文。
3)日文。
2.按钮
1)button的样式整体要统一,例如突出、扁平、3D效果等只能选其一;
2)采用的图片表述相同功能,要采用单一图标。
3.文本框
1)录入长度限制,根据数据库的设计,页面直接限定录入长度(特殊处屏蔽复制、粘贴 (一般是需要重复确认输入的地方) );
2)文本框自身的长度限制,主要考虑页面样式。
4.单选框
1)默认情况要统一,已选择,还是未选。
5.日期控件
1)图标、控件颜色、样式统一;
2)点击控件、文本框均应弹出日期选择框。
6.下拉选择框
1)默认是第一个选项,还是提示请选择一个。
7.提示信息
1)静态文字与它的提示信息一致性,例如静态文字为‘ID’,出错信息显示‘用户ID’;
2)空值时,出错信息需要统一,例如可以采用“静态文字”+不能为空;
3)出现录入错误时,例如可以统一采用“静态文字”+格式不符合要求;
4)提示信息标点符号是否标识; 点击上一步,返回的页面上不应残留出错信息;
5)静态提示信息,在录入框右侧,应有录入信息的相应要求的提示文字,达到方便操作的目的;
6)必输项提示信息,必输项提示信息采用统一的标志。
8.导航测试
死导航、乱导航、操作复杂等。
9.链接测试
1)发现404错误。
2)避免死链接情况,执行完相应操作应有返回按钮,返回到相应页面;例如:操作成功后,进入成功提示信息页面,但页面没有返回按钮,无法及时进入操作之前的页面。
10.IE的后退
退出系统,无论直接关闭浏览器或点击后退键,退出都不应再返回系统。
11.分辨率
页面文字显示、样式等要支持常见分辨率,例如CRT显示器的1024*768,LCD的1280*1024。
12.重复提交问题
1)功能操作完成后,鼠标右键点击所在页面,选择弹出菜单的刷新功能,容易出现重复提交问题。
2)功能操作完成后,通过IE的后退键进行重复操作,容易出现重复提交问题。
3)某功能键反应时间延迟时(限制客户端网络带宽等方式来模拟实现),在短时间内重复点击该功能键,容易出现重复提交问题;
13.防止SQL注入式攻击
1)不允许任何直接在jsp页面调用SQL语句,这种情况常发生在系统的后期修改中。
14.用户非授权页面访问
1)每个页面都需要安全验证,防止用户通过直接拷贝具体页面地址等方式,访问系统;
2)页面过期的时间设定,用户在设定时间内未进行任何操作,不允许访问系统。
二、 文本框公共测试用例
1.文本框为字符型
必填项非空校验:
1)必填项未输入--程序应提示错误;
2)必填项只输入若干个空格,未输入其它字符--程序应提示错误;
3) 每个文本框(包括必填项跟非必填项)里都要输入数据,来检验数据是否保存成功。
字段唯一性校验:(不是所有字段都作此项校验,视实际项目情况而定)
1)新增时输入重复的字段值--必须提示友好信息;
2)修改时输入重复的字段值--必须提示友好信息;
字段长度校验:
1)输入[最小字符数-1]--程序应提示错误;
2)输入[最小字符数]--OK;
3)输入[最小字符数+1]--OK;
4)输入[最大字符数-1]--OK;
5)输入[最大字符数]--OK;
6)输入[最大字符数+1]--程序应提示错误;
字段为特殊字符校验:
1)输入域如对某些字符禁止输入时,限制是否成功,提示信息是否友好;
2)中文、英文、空格,数字,字符,下划线、单引号 等所有特殊字符的组合 ;
3)所有特殊字符都必须进行测试(!~@#$^&*()_+{}|:“<>?/.,;‘[]\=-`¥……()--:《》?、。,;’【】、=-? )
字段为特殊代码校验:
1)输入html代码:比如”你好”;--必须以文本的形式将代码显示出来。
2)输入JavaScript代码:比如;--必须以文本的形式将代码显示出来。
多行文本框输入:
1)是否允许回车换行 ;
2)保存后再显示能够保持输入时的格式 ;
3)仅输入回车换行,检查能否正确保存;若能,查看保存结果。若不能,查看是否有正确提示 ;
4)仅输入空格,检查能否正确保存;若能,查看保存结果。若不能,查看是否有正确提示 。
5)查询数据时,要考虑空格的介入。
2.文本框为数值型
边界值:
1)输入[最小值-1]--程序应提示错误;
2)输入[最小值]--OK;
3)输入[最大值]--OK;
4)输入[最大值+1]--程序应提示错误;
位数:
1)输入[限制位数]--OK;
2)输入[限制位数+1]--根据实际项目而定,是否自动四舍五入成限制位数,还是提示信息;
3)输入[限制位数-1]--OK;
异常值、特殊值:
1)输入非数值型数据:汉字、字母、字符--程序应提示错误;
2)输入负数--根据实际项目而定,如果不允许输入负数,必须提示友好信息;
3)字段禁止直接输入非数值型数据时,使用“粘贴”、“拷贝”功能尝试输入,并测试能否正常提交保存--只能使用“粘贴”、“拷贝”方法输入的特殊字符应无法保存,并应给出相应提示 ;
4)全角数字和半角数字的情况--全角数字不能保存,提示友好信息,半角数字正常保存;
5)首位为零的数值:如01=1--视实际项目情况而定;
3.文本框为日期型
合法性检查:
1)日输入[0日]--程序应提示错误;
2)日输入[1日]--OK;
3)日输入[32日]--程序应提示错误;
4)月输入[1、3、5、7、8、10、12月]、日输入[31日]--OK;
5)月输入[4、6、9、11月]、日输入[30日]--OK;
6)月输入[4、6、9、11月]、日输入[31日]--程序应提示错误;
7)输入非闰年,月输入[2月]、日输入[28日],比如2009.2.28--OK;
8)输入非闰年,月输入[2月]、日输入[29日],比如2009.2.29--程序应提示错误;
9)(闰年)月输入[2月]、日输入[29日],比如2008.2.29--OK;
10)(闰年)月输入[2月]、日输入[30日],比如2008.2.30--程序应提示错误;
12)月输入[1月]--OK;
13)月输入[12月]--OK;
14)月输入[13月] --程序应提示错误;
格式检查:
1)不合法格式:20##-09、 20##-09 -、200-2-2;
2)视具体项目而定是否合法:2009/09/01、2009.09.01 、20090901、20##-09-01 ;
异常值、特殊值:
1)输入汉字、字母、字符--程序应提示错误;
4.文本框为时间型
合法性检查:
1)时输入[24时] --程序应提示错误;
2)时输入[00时] --OK;
3)分输入[60分] --程序应提示错误;
4)分输入[59分] --OK;
5)分输入[00分] --OK;
6)秒输入[60秒] --程序应提示错误;
7)秒输入[59秒] --OK;
8)秒输入[00秒] --OK;
格式检查:
1)不合法格式:12:30:、 123000;
2)视具体项目而定是否合法:12:30、 1:3:0;
异常值、特殊值:
1)输入汉字、字母、字符--程序应提示错误;
2)系统中所涉及时间是否取服务器时间;
三、 上传和导出公共测试用例
1.上传图片
对于上传的文件,假设系统要求上传的文件为jpg或gif格式图片,大小为<=5M的文件,我们在设计测试用例时,应该从以下几个方面进行考虑:
1)文件类型正确,文件大小合适的校验
例如:上传一种jpg或gif的格式图片,文件大小为4.9M,结果为上传成功
2)文件类型正确,文件大小合适的校验
例如:上传一种jpg或gif的格式图片,文件大小为5M,结果为上传成功
3)文件类型正确,文件大小不合适的校验
例如:上传一种jpg或gif的格式图片,文件大小为5.1M,提示为:“上传的附件中大小不能超过5M”
4)文件类型错误,文件大小合适的校验
例如:上传.doc、.xls、ppt、bmp、jpeg、psd、tiff、tga、png、swf、svg、pcx、dxf、wmf、emf、lic、eps、.txt等格式文件,文件大小合适,提示“只能上传jpg或gif格式图片”
5)文件类型和文件大小合法,上传一个0kb的图片,提示信息:“请重新上传文件,或者是不能上传0kb的图片”
6)文件类型和文件大小合法,上传一个正在使用中的图片(即打开该图片,再上传该图片),上传成功
7)文件类型和文件大小合法,手动输入一个存在的图片地址,点击上传,上传成功
8)文件类型和文件大小合法,手动输入一个不存在的图片地址,点击上传,提示:“请正确选择要上传的文件”
9)文件类型和大小都合法,手动输入一个存在的图片名称,点击上传,一般情况下系统会提示:“请正确选择要上传的文件的路径”
2.文件导出
1)验证导出文件名长度,根据具体情况而定
2)验证导出文件为空的情况
3)验证导出文件名为特殊字符的情况
4)验证导出全部资料的情况,导出的信息是否正确
5)验证导出部分资料的情况,导出的信息是否正确
6)验证导出大量数据时的时间是否在合理的时间范围内
7)验证导出目的磁盘空间已满的情况下,导出是否有友好的处理方式
8)验证导出目的的文件夹为只读的情况下,导出时是否有友好的的提示信息
3.文件上传
页面
1)页面美观性、易用性(键盘和鼠标的操作、tab跳转的顺序是否正确)
2)按钮文字正确性
3)说明文字是否正确
4)正确/错误的提示文字是否正确
5)提示当前位置是否正确,并且和其他页面保持一致格式
6)必添项的标示是否正确
功能
1)路径是否可以手工输入(手工输入的时候有没有限长)
2)上传文件超过最大值是在提交前校验还是提交后校验
3)上传文件格式是否全部支持(图片:gif/jpg/bmp...文档:doc/sxw/xls...压缩包:zip/rar...安装文件:exe/msi)
4)上传文件是否支持中文名称
5)文件名称的最大值、最小值、特殊字符(包含空格)、使用程序语句是否会对其造成影响、中文名称是否能正常显示
4.文件下载
功能
1)右键另存为是否可以正确下载文件,并且记录下载次数
i. ?工具下载是否正确,并且记录下载次数
2)单击下载是提示下载还是在页面打开
ii. ?直接打开是否显示正确
iii. ?对于本机没有安装工具的文件是否能够打开,是否能给出正确的提示
iv. ?对于直接在页面内打开的内容是否能够显示正常,页面美观性
v. ?保存到本地是否能正确显示? 取消下载是否会纪录下载次数
3)下载次数是否被正确记录
四、 列表公共测试用例
1.列表页面显示
1) 确认页面的默认排序方式,字段+升降续;
2) 含link的列,验证其有效性,即,点击后的跳转是否正确;
3) 第一列的选择框,“全选”和“部分选择”需有效;部分选中时,全选按钮应自动取消。
2.顶部搜索功能
1)逐个测试每个搜索条件的有效性;
2)做2-3个组合条件的查询,验证结果;合计共有N+3个搜索条件的测试。
3)有时间区间的,验证列表项的开始到结束时间 和 选择区间有交叉,则为有效,且包含所选日期的记录;
4)条件中,开始时间不能大于结束时间;
5)搜索条件,在分页显示时,需始终保持有效;
6)点击名为“显示全部”的按钮,需清除所有条件,并显示所有记录。
7)每一次新的搜索执行,都应该去除分页,显示第一页、并回到进入页面时的默认排序方式。
3.右侧或底部的按钮
按功能分成多个用例:
1)单选,多选、全选的情况下,点击按钮执行某个功能,如暂停服务、恢复服务的按钮;
2)跨页选择,在一些选择成员的列表中是应有效的,需进行确认。
4.列表数据的验证
验证从数据库中得到的列表项中每列数据的正确性,要求覆盖不同情况下的值,比如“开通”、“暂停”的服务状态;已使用空间大小和总空间大小等数字的正确性。可考虑结合其他用例来描述,但必须覆盖到。
5.列表按标题的排序
1)检查每个列标题,要求点击后能按其进行排序:第一次点击为正序,以后每次点击为升、降续的切换。
2)进入下一页、上一页,以及任意分页显示时,条件需始终保持有效。
6.分页
1)“第2页/共8页 每页 10条/共 79条”中的分页数据必须正确;
2) 第一页、 上一页、下一页、最后一页的link在当前上下文有意义时显示,否则隐藏或显示为文本标签;
3)填入某个数字,点击“跳转到”按钮,到正确的页数;
另外请考虑每个文本框输入的有效性,比如日期、域名、跳转到某页的文本框的能接受的值,具体可参考需求文档
对于报表中的所有字段值都应该有明确的定义,对于无意义的字段值,不应该显示空,应显示“--”或“/”,表示该字段值无意义。
1.5
表单测试
表单测试主要分为以下几个方面:
1)注册、登录功能是否实现;
2)提交、清空按钮功能是否实现;
3)修改表单与注册页面数据项是否相同,修改表单是否对重名做验证;
4)提交的数据是否能正确保存到后台数据库中(后台数据库中的数据应与前台录入内容完
全一致,数据不会丢失或被改变);
5)表单提交,删除,修改后是否有提示信息;提示、警告、或错误说明应该清楚、明了、恰当。
6)浏览器的前进、后退、刷新按钮,是否会造成数据重现或页面报错;
7)提交表单是否支持回车键和Tab键;Tab键的顺序与控件排列顺序要一致,目前流行总体从上倒下,同时行间从左到右的方式
8)下拉列表功能是否实现和数据是否完整(例如:省份和市区下拉列表数据是否互动);
附件2 界面测试公共测试用例
JUnit4是JUnit框架有史以来的最大改进,其主要目标便是利用Java5的Annotation特性简化测试用例的编写。
一、Annotation 提供了一条与程序元素关联任何信息或者任何元数据(metadata )的途径。从某些方面看,annotation 就像修饰符一样被使用,并应用于包、类型、构造方法、方法、成员变量、参数、本地变量的声明中。这些信息被存储在annotation 的“name=value” 结构对中。 annotation 类型是一种接口,能够通过java 反射
API 的方式提供对其信息的访问。
首先,看一段注解单元的例子:
public class AddOperationTest extends TestCase{
public AddOperationTest() {
}
@Before
public void setUp() throws Exception {
}
@After
public void tearDown() throws Exception {
}
@Test
public void add() {
System.out.println(\"add\");
int x = 0;
int y = 0;
AddOperation instance = new AddOperation();
int expResult = 0;
int result = instance.add(x, y);
assertEquals(expResult, result);
}
}
从上面的例子可以看到在JUnit 4中还引入了一些其他的元数据,下面一一介绍:
@Before:
使用了该元数据的方法在每个测试方法执行之前都要执行一次。
@After:
使用了该元数据的方法在每个测试方法执行之后要执行一次。
注意:@Before和@After标示的方法只能各有一个。这个相当于取代了JUnit以前版本中的setUp和tearDown
方法当然你还可以继续叫这个名字,不过JUnit不会霸道的要求你这么做了。
@Test(expected=*.class)
在JUnit4.0之前,对错误的测试,我们只能通过fail来产生一个错误,并在try块里面assertTrue(true)
来测试。现在,通过@Test元数据中的expected属性。expected属性的值是一个异常的类型
@Test(timeout=xxx):
该元数据传入了一个时间(毫秒)给测试方法,如果测试方法在制定的时间之内没有运行完,则测试也失败。
@ignore:
该元数据标记的测试方法在测试中会被忽略。当测试的方法还没有实现,或者测试的方法已经过时,或者在某
种条件下才能测试该方法(比如需要一个数据库联接,而在本地测试的时候,数据库并没有连接),那么使用该标签
来标示这个方法。同时,你可以为该标签传递一个String的参数,来表明为什么会忽略这个测试方法。比如:
@lgnore(“该方法还没有实现”),在执行的时候,仅会报告该方法没有实现,而不会运行测试方法。
二、在Eclipse中使用Junit4进行单元测试
我们在编写大型程序的时候,需要写成千上万个方法或函数,这些函数的功能可能很强大,但我们在程序中只用
到该函数的一小部分功能,并且经过调试可以确定,这一小部分功能是正确的。但是,我们同时应该确保每一个函数
都完全正确,因为如果我们今后如果对程序进行扩展,用到了某个函数的其他功能,而这个功能有bug的话,那绝对
是一件非常郁闷的事情。所以说,每编写完一个函数之后,都应该对这个函数的方方面面进行测试,这样的测试我们
称之为单元测试。传统的编程方式,进行单元测试是一件很麻烦的事情,你要重新写另外一个程序,在该程序中调用
你需要测试的方法,并且仔细观察运行结果,看看是否有错。正因为如此麻烦,所以程序员们编写单元测试的热情不
是很高。于是有一个牛人推出了单元测试包,大大简化了进行单元测试所要做的工作,这就是JUnit4。本文简要介绍
一下使用JUnit4进行单元测试的方法。
先来体验一下单元测试的快感!
首先新建一个项目叫JUnit_Test,我们编写一个Calculator类,这是一个能够简单实现加减乘除、平方、开方的
计算器类,然后对这些功能进行单元测试。这个类并不是很完美,我们故意保留了一些Bug用于演示,这些Bug在注释
中都有说明。该类代码如下:
public class Calculator {
private static int result; // 静态变量,用于存储运行结果
public void add(int n){
result = result + n;
}
public void substract(int n){
result = result - 1; //Bug: 正确的应该是 result =result-n
}
public void multiply(int n){
} // 此方法尚未写好
public void divide(int n){
result = result/n;
}
public void square(int n){
result = n * n;
}
public void squareRoot(int n){
for (; ;) ; //Bug : 死循环
}
public void clear(){ // 将结果清零
result = 0;
}
public int getResult(){
return result;
}
}
第二步:导入Junit软件包 属性--java构建路径--Libraries--Add Library--Junit。
第三步:新建JUnit Test Case(勾选上setUp选项,可以产生before注解的相关方法),勾选上需要测试的
方法。
之后系统会自动生成一个新类CalculatorTest,里面包含一些空的测试用例。你只需要将这些测试用例稍作修
改即可使用。完整的CalculatorTest代码如下:
public class CalculatorTest {
private Calculator calculator = new Calculator();
@Before
public void setUp() throws Exception {
calculator.clear();
}
@Test
public void testAdd() {
calculator.add(2);
calculator.add(3);
assertEquals(5,calculator.getResult());
}
@Test
public void testSubstract() {
calculator.substract(8);
calculator.substract(2);
assertEquals(6,calculator.getResult());
}
@Ignore("Multiply() Not yet implemented")
@Test
public void testMultiply() {
calculator.multiply(1);
calculator.multiply(4);
assertEquals(4,calculator.getResult());
}
@Test
public void testDivide() {
calculator.divide(6);
calculator.divide(2);
assertEquals(3,calculator.getResult());
}
}
第四步,运行测试代码:按照上述代码修改完毕后,我们在CalculatorTest类上点右键,选“Run As JUnit
Test”来运行我们的测试。 至此,我们已经完整体验了在Eclipse中使用JUnit的方法。
三、在Eclipse中使用Junit4进行单元测试
初级篇中我们使用Eclipse自动生成了一个测试框架,在这篇文章中,我们来仔细分析一下这个测试框架中的每
一个细节,知其然更要知其所以然,才能更加熟练地应用JUnit4。
一、包含必要地Package
在测试类中用到了JUnit4框架,自然要把相应地Package包含进来。最主要地一个Package就是org.junit.*。把
它包含进来之后,绝大部分功能就有了。还有一句话也非常地重要“import static org.junit.Assert.*;”,我们
在测试的时候使用的一系列assertEquals方法就来自这个包。大家注意一下,这是一个静态包含(static),是
JDK5中新增添的一个功能。也就是说,assertEquals是Assert类中的一系列的静态方法,一般的使用方式是Assert.
assertEquals(),但是使用了静态包含后,前面的类名就可以省略了,使用起来更加的方便。
二、测试类的声明
大家注意到,我们的测试类是一个独立的类,没有任何父类。测试类的名字也可以任意命名,没有任何局限
性。所以我们不能通过类的声明来判断它是不是一个测试类,它与普通类的区别在于它内部的方法的声明,我们接着
会讲到。
三、创建一个待测试的对象。
你要测试哪个类,那么你首先就要创建一个该类的对象。正如上一篇文章中的代码:
private static Calculator calculator = new Calculator();
为了测试Calculator类,我们必须创建一个calculator对象。
四、测试方法的声明
在测试类中,并不是每一个方法都是用于测试的,你必须使用“标注”来明确表明哪些是测试方法。“标注
”也是JDK5的一个新特性,用在此处非常恰当。我们可以看到,在某些方法的前有@Before、@Test、@Ignore等字样
,这些就是标注,以一个“@”作为开头。这些标注都是JUnit4自定义的,熟练掌握这些标注的含义非常重要。
五、编写一个简单的测试方法。
首先,你要在方法的前面使用@Test标注,以表明这是一个测试方法。对于方法的声明也有如下要求:名字可
以随便取,没有任何限制,但是返回值必须为void,而且不能有任何参数。如果违反这些规定,会在运行时抛出一个
异常。至于方法内该写些什么,那就要看你需要测试些什么了。比如:
@Test
public void testAdd() {
calculator.add(2);
calculator.add(3);
assertEquals(5, calculator.getResult());
}
我们想测试一下“加法”功能时候正确,就在测试方法中调用几次add函数,初始值为0,先加2,再加3,我们
期待的结果应该是5。如果最终实际结果也是5,则说明add方法是正确的,反之说明它是错的。assertEquals(5,
calculator.getResult());就是来判断期待结果和实际结果是否相等,第一个参数填写期待结果,第二个参数填写
实际结果,也就是通过计算得到的结果。这样写好之后,JUnit会自动进行测试并把测试结果反馈给用户。
六、忽略测试某些尚未完成的方法。
如果你在写程序前做了很好的规划,那么哪些方法是什么功能都应该实现定下来。因此,即使该方法尚未完
成,他的具体功能也是确定的,这也就意味着你可以为他编写测试用例。但是,如果你已经把该方法的测试用例写完
,但该方法尚未完成,那么测试的时候一定是“失败”。这种失败和真正的失败是有区别的,因此JUnit提供了一种
方法来区别他们,那就是在这种测试函数的前面加上@Ignore标注,这个标注的含义就是“某些方法尚未完成,暂不
参与此次测试”。这样的话测试结果就会提示你有几个测试被忽略,而不是失败。一旦你完成了相应函数,只需要把
@Ignore标注删去,就可以进行正常的测试。
七、Fixture(暂且翻译为“固定代码段”)
Fixture的含义就是“在某些阶段必然被调用的代码”。比如我们上面的测试,由于只声明了一个
Calculator对象,他的初始值是0,但是测试完加法操作后,他的值就不是0了;接下来测试减法操作,就必然要考虑
上次加法操作的结果。这绝对是一个很糟糕的设计!我们非常希望每一个测试都是独立的,相互之间没有任何耦合度
。因此,我们就很有必要在执行每一个测试之前,对Calculator对象进行一个“复原”操作,以消除其他测试造成的
影响。因此,“在任何一个测试执行之前必须执行的代码”就是一个Fixture,我们用@Before来标注它,如前面例子
所示:
@Before
public void setUp() throws Exception {
calculator.clear();
}
这里不在需要@Test标注,因为这不是一个test,而是一个Fixture。同理,如果“在任何测试执行之后需要
进行的收尾工作”也是一个Fixture,使用@After来标注。由于本例比较简单,没有用到此功能。
三、在Eclipse中使用Junit4进行单元测试(高级篇)
一、高级Fixture
上一篇文章中我们介绍了两个Fixture标注,分别是@Before和@After,我们来看看他们是否适合完成如下功能 :有一个类是负责对大文件(超过500兆)进行读写,他的每一个方法都是对文件进行操作。换句话说,在调用每一 个方法之前,我们都要打开一个大文件并读入文件内容,这绝对是一个非常耗费时间的操作。如果我们使用@Before
和@After,那么每次测试都要读取一次文件,效率及其低下。这里我们所希望的是在所有测试一开始读一次文件,所 有测试结束之后释放文件,而不是每次测试都读文件。JUnit的作者显然也考虑到了这个问题,它给出了 @BeforeClass 和 @AfterClass两个Fixture来帮我们实现这个功能。从名字上就可以看出,用这两个Fixture标注的 函数,只在测试用例初始化时执行@BeforeClass方法,当所有测试执行完毕之后,执行@AfterClass进行收尾工作。
在这里要注意一下,每个测试类只能有一个方法被标注为@BeforeClass 或 @AfterClass,并且该方法必须是Public
和Static的。
二、限时测试。
还记得我在初级篇中给出的例子吗,那个求平方根的函数有Bug,是个死循环:
public void squareRoot(int n) {
for (; ;) ; //Bug : 死循环
}
如果测试的时候遇到死循环,你的脸上绝对不会露出笑容。因此,对于那些逻辑很复杂,循环嵌套比较深的
程序,很有可能出现死循环,因此一定要采取一些预防措施。限时测试是一个很好的解决方案。我们给这些测试函数
设定一个执行时间,超过了这个时间,他们就会被系统强行终止,并且系统还会向你汇报该函数结束的原因是因为超
时,这样你就可以发现这些Bug了。要实现这一功能,只需要给@Test标注加一个参数即可,代码如下:
@Test(timeout = 1000)
public void squareRoot() ...{
calculator.squareRoot(4);
assertEquals(2, calculator.getResult());
}
Timeout参数表明了你要设定的时间,单位为毫秒,因此1000就代表1秒。
三、 测试异常
JAVA中的异常处理也是一个重点,因此你经常会编写一些需要抛出异常的函数。那么,如果你觉得一个函数应该
抛出异常,但是它没抛出,这算不算Bug呢?这当然是Bug,并JUnit也考虑到了这一点,来帮助我们找到这种Bug。例
如,我们写的计算器类有除法功能,如果除数是一个0,那么必然要抛出“除0异常”。因此,我们很有必要对这些进
行测试。代码如下:
@Test(expected = ArithmeticException.class)
public void divideByZero() ...{
calculator.divide(0);
}
如上述代码所示,我们需要使用@Test标注的expected属性,将我们要检验的异常传递给他,这样JUnit框
架就能自动帮我们检测是否抛出了我们指定的异常。
四、Runner (运行器)
大家有没有想过这个问题,当你把测试代码提交给JUnit框架后,框架如何来运行你的代码呢?答案就是——
Runner。在JUnit中有很多个Runner,他们负责调用你的测试代码,每一个Runner都有各自的特殊功能,你要根据需
要选择不同的Runner来运行你的测试代码。可能你会觉得奇怪,前面我们写了那么多测试,并没有明确指定一个
Runner啊?这是因为JUnit中有一个默认Runner,如果你没有指定,那么系统自动使用默认Runner来运行你的代码。
换句话说,下面两段代码含义是完全一样的:
import org.junit.internal.runners.TestClassRunner;
import org.junit.runner.RunWith;
//使用了系统默认的TestClassRunner,与下面代码完全一样
public class CalculatorTest {...}
@RunWith(TestClassRunner.class)
public class CalculatorTest {...}
从上述例子可以看出,要想指定一个Runner,需要使用@RunWith标注,并且把你所指定的Runner作为参数传
递给它。另外一个要注意的是,@RunWith是用来修饰类的,而不是用来修饰函数的。只要对一个类指定了Runner,那
么这个类中的所有函数都被这个Runner来调用。最后,不要忘了包含相应的Package哦,上面的例子对这一点写的很
清楚了。接下来,我会向你们展示其他Runner的特有功能。
五、 参数化测试。
你可能遇到过这样的函数,它的参数有许多特殊值,或者说他的参数分为很多个区域。比如,一个对考试分
数进行评价的函数,返回值分别为“优秀,良好,一般,及格,不及格”,因此你在编写测试的时候,至少要写5个
测试,把这5中情况都包含了,这确实是一件很麻烦的事情。我们还使用我们先前的例子,测试一下“计算一个数的平方”这个函数,暂且分三类:正数、0、负数。
测试代码如下:
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
public class AdvancedTest {
private static Calculator calculator = new Calculator();
@Before
public void clearCalculator() ...{
calculator.clear();
}
@Test
public void square1() ...{
calculator.square(2);
assertEquals(4, calculator.getResult());
}
@Test
public void square2() ...{
calculator.square(0);
assertEquals(0, calculator.getResult());
}
@Test
public void square3() ...{
calculator.square(-3);
assertEquals(9, calculator.getResult());
}
}
为了简化类似的测试,JUnit4提出了“参数化测试”的概念,只写一个测试函数,把这若干种情况作为参数
传递进去,一次性的完成测试。代码如下:
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import java.util.Arrays;
import java.util.Collection;
@RunWith(Parameterized.class)
public class SquareTest {
private static Calculator calculator = new Calculator();
private int param;
private int result;
@Parameters
public static Collection data() ...{
return Arrays.asList(new Object[][]{{2, 4},{0, 0},{-3, 9}});
}
//构造函数,对变量进行初始化
public SquareTest(int param, int result) ...{
this.param = param;
this.result = result;
}
@Test
public void square() {
calculator.square(param);
assertEquals(result, calculator.getResult());
}
}
下面我们对上述代码进行分析。首先,你要为这种测试专门生成一个新的类,而不能与其他测试共用同一个
类,此例中我们定义了一个SquareTest类。然后,你要为这个类指定一个Runner,而不能使用默认的Runner了,因
为特殊的功能要用特殊的Runner嘛。@RunWith(Parameterized.class)这条语句就是为这个类指定了一个
ParameterizedRunner。第二步,定义一个待测试的类,并且定义两个变量,一个用于存放参数,一个用于存放期待
的结果。接下来,定义测试数据的集合,也就是上述的data()方法,该方法可以任意命名,但是必须使用
@Parameters标注进行修饰。这个方法的框架就不予解释了,大家只需要注意其中的数据,是一个二维数组,数据两
两一组,每组中的这两个数据,一个是参数,一个是你预期的结果。比如我们的第一组{2, 4},2就是参数,4就是预
期的结果。这两个数据的顺序无所谓,谁前谁后都可以。之后是构造函数,其功能就是对先前定义的两个参数进行初
始化。在这里你可要注意一下参数的顺序了,要和上面的数据集合的顺序保持一致。如果前面的顺序是{参数,期待
的结果},那么你构造函数的顺序也要是“构造函数(参数, 期待的结果)”,反之亦然。最后就是写一个简单的测试
例了,和前面介绍过的写法完全一样,在此就不多说。
六、 打包测试。
通过前面的介绍我们可以感觉到,在一个项目中,只写一个测试类是不可能的,我们会写出很多很多个测试
类。可是这些测试类必须一个一个的执行,也是比较麻烦的事情。鉴于此,JUnit为我们提供了打包测试的功能,将
所有需要运行的测试类集中起来,一次性的运行完毕,大大的方便了我们的测试工作。具体代码如下:
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@RunWith(Suite.class)
@Suite.SuiteClasses({
CalculatorTest.class,
SquareTest.class
})
public class AllCalculatorTests {}
大家可以看到,这个功能也需要使用一个特殊的Runner,因此我们需要向@RunWith标注传递一个参数
Suite.class。同时,我们还需要另外一个标注@Suite.SuiteClasses,来表明这个类是一个打包测试类。我们把需
要打包的类作为参数传递给该标注就可以了。有了这两个标注之后,就已经完整的表达了所有的含义,因此下面的类
已经无关紧要,随便起一个类名,内容全部为空既可。
四、整合篇,spring 和junit4
1. 加入依赖包
使用Spring的测试框架需要加入以下依赖包:
JUnit 4 (官方下载:https://github.com/KentBeck/junit/downloads)
Spring Test (Spring框架中的test包)
Spring 相关其他依赖包(不再赘述了,就是context等包)
2. 创建测试源目录和包
在此,推荐创建一个和src平级的源文件目录,因为src内的类都是为日后产品准备的,而此处的类仅仅用于测试
。而包的名称可以和src中的目录同名,这样由于在test源目录中,所以不会有冲突,而且名称又一模一样,更方便
检索。
3. 创建测试类
创建一个测试用的类,推荐名称为 “被测试类名称 + Test”。
测试类应该继承与 AbstractJUnit4SpringContextTests 或 AbstractTransactionalJUnit4
SpringContextTests
对于 AbstractJUnit4springcontextTests 和 AbstractTransactionalJUnit4SpringContextTests 类的选择 :如果在你的测试类中,需要用到事务管理(比如要在测试结果出来之后回滚测试内容),就可以使用 AbstractTransactionalJUnit4SpringTests类。事务管理的使用方法和正常使用Spring事务管理是一样的。再此需 要注意的是,如果想要使用声明式事务管理,即使用AbstractTransactionalJUnitSpringContextTests类,请在 applicationContext.xml文件中加入transactionManager bean:
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
如果没有添加上述bean,将会抛出NoSuchBeanDefinitionException,指明 No bean named
'transactionManager' is definded.
4. 配置测试类
添加如下内容在class前,用于配置applicationContext.xml文件的位置。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
5. 创建测试方法
创建测试用方法,推荐名称为 “被测方法名称+ Test”。
测试方法上方加入 @Test
6. 通过JUnit 4 执行
右键方法名,选择则“Run As”→“JUnit Test”即可
附录1:整体测试类文件
package com.mb.dao;
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.mb.entity.User;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class UserDaoTest extends AbstractJUnit4SpringContextTests {
@Resource
private UserDaoInterface userDao;
@Test
public void saveTest() {
User user1 = new User();
user1.setUsername("rainisic");
user1.setPassword("123456");
user1.setNickName("rainisic");
user1.setEmail("rainisic@gmail.com");
User user2 = new User();
user2.setUsername("admin");
user2.setPassword("123456");
user2.setNickName("admin");
user2.setEmail("admin@admin.com");
User user3 = new User();
user3.setUsername("test");
user3.setPassword("123456");
user3.setNickName("test");
user3.setEmail("test@gmail.com");
userDao.save(user1);
userDao.save(user2);
userDao.save(user3);
}
}
例2:
@RunWith(SpringJUnit4ClassRunner.class) //指定测试用例的运行器 这里是指定了Junit4
@ContextConfiguration({"/applicationContext-hibernate.xml","/applicationContext-beans.xml"}) //指定Spring的配置文件 /为classpath下
//@Transactional //对所有的测试方法都使用事务,并在测试完成后回滚事务
public class UserServiceImplTest {
// @Autowired
// private ApplicationContext appplicationContext; //自动注入applicationContext,这样就可以使用appli*.getBean("beanName")
@Resource //会自动注入 default by type
private UserDao userDao;
@Resource
private UserService userService;
@Before //在每个测试用例方法之前都会执行
public void init(){
}
@After //在每个测试用例执行完之后执行
public void destory(){
}
@Test
@Transactional //使用该注释会使用事务,而且在测试完成之后会回滚事务,也就是说在该方法中做出的一切操作都不会对数据库中的数据产生任何影响
// @Rollback(false) //这里设置为false,就让事务不回滚
public void testAdd(){
Assert.assertNotNull(userDao);
Assert.assertNotNull(userService);
userDao.add(new User("userDao1","world!"));
userService.registerUser(new User("UserService1","world!"));
}
public void testTest() {
}
}
附件3 缺陷报告模板
附件4 测试用例设计参考
一、注册测试用例
二、登陆测试用例
三、修改密码测试用例
附件5 课程设计报告封面
上海电力学院
软件测试课程设计
题 目: “我校教学大纲与教学进度表在线管理系统”
软件测试报告
学 号: 姓 名:
院 系: 计算机科学与技术学院
专业年级: 软件工程2012级
20##年7月10日