单元测试、集成测试之入门一【读书札记】
?
【格言1】若程序的某项功能没有经过自动测试,那该功能基本等于不存在
【格言2】敏捷测试的第一步就是不要敏捷,先一步步把自动化做好,把持续集成做起来,创建更多的测试工具来提高测试效率,把质量反馈系统做起来,代码质量检查做起来等等,这些建立起来后,你就很敏捷了
【格言3】如果在功能测试和单元测试选一个来做的话,那你应该选择功能测试,70%的应用程序错误都可以通过功能测试来找回的。
?
?
1、《junit in action》 电子工业出版社
2、《软件测试的艺术》机械工业出版社【力荐】
1、什么叫做测试阶段,什么叫做测试方法?
??? 测试阶段:单元测试、集成测试、功能测试、系统测试,这个叫做测试阶段
??? 测试方法:从大的分类讲,白盒测试、黑盒测试、灰盒测试、人工测试,这个叫做测试方法
2、什么样的测试叫做单元测试?单元到底是什么,多小多大的东西才叫单元?
??? 百度百科说法:要根据实际情况去判定其具体含义,如C语言中单元指一个函数,Java里单元指一个类,图形化的软件中可以指一个窗口或一个菜单等。总的来说,单元就是人为规定的最小的被测功能模块。
??? 《junit in action》说法:单元测试测的是独立的一个工作单元。在java应用程序中,“独立的一个工作单元”常常指的是一个方法。一个工作单元是一项任务,它不依赖于其他任务的完成。
??? 《软件测试的艺术》说法:单元测试是对程序中的单个子程序、子程序或过程进行测试的过程,是对构成程序的较小模块的测试。
??? 各位看官,你们看懂了么?反正我没看懂。上面有说单元是java中的一个类,又说是java代码中的一个函数方法,这到底是闹哪样。以下是我猜测的结论:被测单元的粒度大小是由程序员规定的,“单元”不仅仅是对应一个代码中方法或某个类,应该说一个具有独立任务的功能代码短(软件编程有一个单一原则,一个方法对应一个功能点)。
3、什么样的测试叫做集成测试?
???? 单元A ?+ ?单元B = 更大单元C
???? 单元A:保存用户数据信息到数据库
???? 单元B:下发邮件(短信)到用户邮箱(手机)
???? 更大单元C:注册功能
插曲,请回过头来理解这句话:“《junit in action》一个工作单元是一项任务,它不依赖于其他任务的完成”。第一:单元A和单元B互不依赖;第二:输入可以使用其他单元的输出数据
集成测试:各个单元组合测试,完成某一大功能的测试。单元A测试正确之后,把单元B加入测试。注意:尽量使用增量测试,就是说A,B,AB,C,ABC,D,ABCD这样顺序,而不是A,B,C,D,ABCD这样,虽然少了一点,但是错误不好定位。
4、什么样的测试叫做功能测试?
??? 看看上面的注册功能测试C,可以当作功能测试中的一个步骤了。
??? 功能测试:测试软件表现的是不是符合spec上面规定的
5、什么样的测试叫做系统测试?
??? 系统测试:测试软件表现的是不是符合最初目标(用户需求),包含安全性测试、性能测试、容量测试、可靠性测试等。
6、黑盒测试有哪些方法?
??? 黑盒测试:有正确输入和预期的输出,用正确的输入来测试软件,看看输出数据(表现状态)是否和预期的一致。
我们只讲主要的:等价类测试、边界分析值测试、错误猜测、因果图等方法
等价类测试:
??? 有效(正确的)输入作为一类,其他无效的作为另一类,注意了其他无效的应该是分开的
??? 比如用户名8到16个字符,正确的有效的一个类:对于8个小于16个
??? 错误的类需要分开,而不能写成这样作为一个等价类:小于8或者大于16,因为编译器遇到小于8的时候,就不会忽略后面的错误了。
??? 错误等价类:1、小于8 ???2、大于16 ??独立性
?
边界测试:一般是对数量、个数啊、是、否、有、无、相同、不同、最高、最低进行边界数据测试(包含输出的结果反推到输入数据,比如y=sinx函数,他对输入x没有边界,但是对输出y是有边界的,那就是当y=1的时候,x的那个值需要被测试)
??? 原则:
??? 1、有效值边界,最大值、最小值、比最小少一点、比最大大一点,比如用户名是8到16位,那么边界测试用例数据包含:8,16,7,17
??? 2、输入和输出是有序的,注意第一个和最后一个元素
??? 3、数据库最大记录数,最小记录数
?
因果图测试:一般是两个输入组合作为条件产生输出的。比如买雪碧,需要两个输入条件1:投入钱币数额2、用户按了哪个按钮。
可能用户投入的是1.5元,按了可乐,那自动饮料机就会输出可乐了。。。输出由两个输入组合决定。
错误猜测:靠猜,可能某些容易犯错误。
?
7、白盒测试有哪些方法?
??? 白盒测试:语句覆盖测试、判定覆盖测试、条件覆盖测试、判定/条件覆盖测试、多重条件覆盖测试等。
??? 亲,在实际项目中比较靠谱的是多重条件覆盖测试,其他的你可以忘掉。
不想看具体说明的,下面可以跳过
-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-
白盒测试:覆盖程序逻辑结构(源代码)的程度,完全的白盒测试是将程序中每条路径都执行到,然而对有带有循环的程序,完成路径测试是不切合实际的。
?
完全路径测试是测试不出来真正的错误。语句覆盖——每条语句都覆盖过——较弱的逻辑覆盖准则
?
判定覆盖或分支覆盖——较强的逻辑覆盖准则。要求必须编写足够的测试用例,使得每一个判断都至少有一个为真和为假的输出结果。每一条语句都必须覆盖过
If(b==2 || a > 1) 这种判断覆盖,他只负责if真和假的路径,测试用例可以这样 b=2 a=1或者b=3 a=1 。但是正确的语句应该是if(b==2 || a <1),这样测试用例测试不出来
?
条件覆盖——要对if中的判断语句每个条件的所有可能都覆盖到,比如IF(A&B) 测试用例可以是:1(A为真,B为假)? 或者 2(A为假,B为真),你瞧瞧A的真假都设计到,B的真假都设计到了,他们满足条件覆盖的测试用例,但是if语句中的then没有被执行。于是引入了判定/条件覆盖
?
判定/条件覆盖准则——较强的测试用例设计准则,每个判断中的每个条件的所有可能的结果至少执行一次,每个判断的所有可能的结果至少执行一次。要求是设计出充足的测试用例。
还是例子IF(A&B) ,1:条件A和B所有可能结果是A为真,A为假,B为真,B为假,
2:判断的所有可能A&B为真 , A&B为假。
测试用例:1(A为真,B为真) 2(A为假,B为假)满足这个准则,想想有问题么?
具体点if(a>0 && b>1) 其中A代表a>0, B代表b>1
测试用例:1(a=2, b=3)真,执行then语句;2(a=-3,b=1)假,不执行then语句。满足上面判定/条件覆盖准则
问题:其实逻辑判断语句b>1是错误的,他应该是b>2正确的逻辑代码是if(a>0 && b>2)
结论:判断/条件覆盖准则的测试用例发现不了这个问题。
?
多重条件覆盖准则——,将每个判定中的所有可能的条件结果进行组合,所有的入口点都至少执行一次。注意了,不是多重判定/条件覆盖准则,但是他满足了判定准则、条件覆盖准则(不用说)、判定/条件覆盖准则。IF(A&B)对于这个,测试用例必须覆盖下面4个组合是:
A
B
结果
0
0
0
0
1
0
1
0
0
1
1
1
\
较上面多了2个
他做到了条件组合,但是并没有做到一个方法内部的判定组合:
If(a>1&& b==0) {
??? X= x /a;?? 。。。。。。。。。。。。。。。。。。。。。。。。。运行1
}
If(a == 2 || x> 1) {
??? X= x + 1;。。。。。。。。。。。。。。。。。。。。。。。。。。。运行2
}
8种条件组合
?
a
b
x
结果
1
>1
=0
?
1
2
>1
<>0
?
×
3
<=1
=0
?
×
4
<=1
<>0
?
×
5
=2
?
>1
2
6
=2
?
<=1
×
7
<>2
?
>1
×
8
<>2
?
<=1
×
?
只要测试用例覆盖了以上的组合就可以了
a
b
x
覆盖了
2
0
4
1,5
2
1
1
2,6
1
0
2
3,7
1
1
1
4,8
?
上面给出的4个具体的测试用例,覆盖了所有的条件组合。同样也覆盖了所有的语句,但是某些组合判定没有被覆盖到。比如1,6组合,运行了语句1,其他不运行。
-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-
总结:从上面几个来看,最完整的应该建议使用多重条件覆盖测试准则。
8、哪个测试阶段会使用某些测试方法?
??? 1、单元测试
??? ?????? 若你是敏捷开发者,单元测试肯定是黑盒测试方法。(因为先写测试代码)
??? ?????? 若不是,单元测试使用白盒测试、黑盒测试多种方法组合
??? 2、集成测试
??? 集成测试是单元测试基础上,如何把单元模块组装起来一起测试,测试方法采用黑盒。组装方式有自顶向下和自下向上两种。
比如之前说的
单元A ?+ ?单元B?+? 单元C = 更大单元D
?
? ??单元A:保存用户数据信息到远程UCenter数据库
???? 单元B:下发邮件(短信)到用户邮箱(手机)
???? 单元C:保存用户数据信息到本地数据库
???? 更大单元D:注册功能,保存成功之后
???? 对于单元D,要求是单元A成功后,才能运行单元B和C,他们的关系A在顶端,BC在下面
???? 自顶向下:A, B, C,AB,ABC
???? 自下向上:B ,C, A,BC,ABC
???? 原则:关键单元先测,然后在组合其他的
注意:A是调用远程接口,我们在开发的时候远程代码还没有完成,那我们该如何完成上面的集成测试了?使用mock,自己模拟写一个A的功能,此功能不处理任何逻辑。或者用stub,需要你实现逻辑。Ps:为什么计算机中把stub翻译成桩,很难理解!!
9、一般测试的步骤是什么样的?
??? 第一步:单元测试
??? ?????? 1、选择测试方法,到底是选择白盒测试、还是黑盒测试
??? ?????? 一:一般是使用组合测试方法,但是如果是敏捷开发方式,只能用黑盒测试方法了
??? ?????? 二:选择白盒测试中的多重条件测试准则
??? ?????? 三:如果接口文档中说输出是由输入条件组合才能得出,请使用黑盒的因果图分析方法
??? ?????? 四:任何情况都要使用边界值分析方法
??? ?????? 五:其他情况,使用等价类和错误猜测技术增加更多的测试用例进行补充
??? ?????? 2、设计测试用例
??? ?????? 根据1中列出来的测试方法来列出测试用例,覆盖白盒测试中的条件组合,
??? ?????? 表格如下:
测试用例编号
输入
预期的输出
注释
1
?
没有返回值,表示成功
?
2
。。。。
。。。。
。。。
??? ?????? 原则1:测试用例尽量少
??? ?????? 原则2:一个测试用例覆盖尽量覆盖多个组合(其实和原则1相辅相成)
3、起单元测试方法名称
??? ?????? 某被测方法或者功能userRegister
??? ?????? 原则1:测试名使用驼峰式xxYyyZzz
??? ?????? 原则2:命名规则,由以下组成test+被测方法+预期输出的类型。如上面测试用例1,他的命名testUserRegisterSuccess。
??? ?????? 原则3:一个测试方法,只处理一种预期类型(个人理解)。
在《junit in action》书中说道:“一个单元测试等于一个测试方法,不要试图把多个测试塞进一个方法” 什么意思啊?看懂了么?
表格如下:
方法名
检查到的测试用例(这里是测试用例表中的序号)
testAccountExistUserInfoNull
9
testAccountExistUsernameExisted
3
testAccountExistEmailExisted
4
testAccountExistMobileNumExisted
6
testAccountExistUserTrue
1、2、5
4、写测试代码方法内部使用Assert.fail(“未测试”);Why?避免遗漏测试方法,养成好习惯:)
?????? 5、最后填充测试方法
??? 原则一:对于assertTrue/assertNotNull/assertNull/assertFalse测试方法,请记住第一个参数sring需要写,便于失败原因。
??? 原则二:把共有初始化行为放在setUp方法中
??? 第二步:集成测试
??? ?????? 1、有时候需要写mock或者stub
??? ?????? 2、重要功能的单元测试先加进来,然后加上不重要的单元
??? 其他:功能测试、系统测试,这里不讲
0、已有模块代码:??????
此模块的测试描述:用户判断用户名、手机号码、邮箱地址是否重复
1、选择测试方法,到底是选择白盒测试、还是黑盒测试
??? N1:选择白盒测试中的多重条件测试
??? N2:选择黑盒测试中的边界值分析法
??? N3:其他补充(错误猜测法)
2、设计测试用例
??? N1:基于上面多重条件测试方法。
把所有的if和while等判断语句找出来
判定(代码行数)
条件
正确结果
错误结果
297
User.getUsername()!=null
用户名不为空
用户名为空
299
USERNAME_EXIST.equals(resultStr)
用户名已经存在
用户名不存在
304
User.getEmail()!=null
邮箱地址不为空
邮箱地址为空
306
EMAIL_EXIST.equals(resultStr)
邮箱地址已经存在
邮箱地址不存在
311
User.getMobile()!=null
手机不为空
手机为空
311
User.getMobile().getMobileNum()!=null
手机号码不为空
手机号码为空
313
MOBILE_EXIST.equals(resultStr)
手机号码已经存在
手机号码不存在
??? 1、用户名为空
2、用户名不为空,用户名重复
3、用户名不为空,用户名不重复
4、邮箱地址为空
5、邮箱地址不为空,邮箱地址重复
6、邮箱地址不为空,邮箱地址不重复
7、手机号码为空
8、手机号码不为空,手机号码重复
9、手机号码不为空,手机号码不重复
?
那么测试用例必须覆盖上面的9个组合,注意了:一个测试用例尽量覆盖多个上面的组合条件
?
测试用例编号
输入
预期的输出
注释
1
username=””
email=”email”//邮箱地址可以注册
mobileNum=””
程序状态不变
Result=0
?
覆盖了条件:1、6、7
2
username=“username”
email=””
mobileNum=””
此用户名不存在数据库中
需要给出数据库预置的内容
程序状态不变
Result=0
?
覆盖了条件:
3、4、7
3
username=”existed_username”
email=””
mobileNum=””
程序返回1
覆盖了条件:
2、4、7
4
email =”existed_ email”
username=””
mobileNum=””
程序返回2
覆盖了条件:
1、5、7
5
mobileNum =“123123123123”
此手机号码不存在数据库中
需要给出数据库预置的内容
Username=””
Email=””
程序状态不变
Result=0
?
覆盖了:1、4、9
6
mobileNum =”32132132131”
此手机号码重复
Username=””
Email=””
程序返回3
覆盖了:1、4、8
7
Username=””
Email=””
mobileNum=””
程序返回4
覆盖了:1、4、7
N2:选择黑盒测试中的边界值分析法
? ????? 还记的上面讲的原则么?
原则:
??? 1、有效值边界,最大值、最小值、比最小少一点、比最大大一点,比如用户名是8到16位,那么边界测试用例数据包含:8,16,7,17
??? 2、输入和输出是有序的,注意第一个和最后一个元素
??? 3、数据库最大记录数,最小记录数
但是我发现这个单元很难找到边界值,单元并没有对输入值范围、大小进行明确的规定。读者,您有好的用例么?帮忙给出。谢谢了。
N3:其他补充(错误猜测法)
?
User如果为空,上面的方法就是废物,而且运行期会抛出空指针异常。所以有时候设计用例的时候,会反过来发现代码设计的有问题。这部分白盒测试没办法指导。
测试用例编号
输入
预期的输出
注释
8
User=null
程序返回4
返回是无效参数
其他的错误猜想,没想到,请各位看官指点一二。
3、起单元测试方法名称
?
方法
检查到的测试用例
testAccountExistUserInfoNull
7,8
testAccountExistUsernameExisted
3
testAccountExistEmailExisted
4
testAccountExistMobileNumExisted
6
testAccountExistUserTrue
1、2、5
?
4、写测试代码方法内部使用Assert.fail(“未测试”);Why?避免遗漏测试方法,养成好习惯:)
???
5、最后填充测试方法
待续~
?