本文参考《开发者测试》–王亚兴、《软件测试技术指南》–斛嘉乙
软件缺陷(Defect),常常被称为Bug,所谓软件缺陷就是指计算机软件或程序中存在的某种破坏正常运行能力的问题、错误,或者隐藏的功能缺陷。缺陷的存在会导致软件产品在某种程度上不能满足用户的需要。
在IEEE中对缺陷有一个标准的定义如下:
(1)从产品内部看,是指软件产品开发或维护过程中存在的错误、毛病等各种问题。
(2) 从产品外部看,是指系统所需要实现的某种功能的失效或违背。
早在1947年9月9日,Bug(英文译文“臭虫”或“虫子”)一词,由美国海军的编程员,编译器的发明者格蕾斯·哈珀(GraceHopper)提出,她发现计算机死机的问题,竟然是一只飞蛾导致的。她小心地用镊子将蛾子夹出来,用透明胶布帖到“事件记录本”中,并注明“第一个发现虫子的实例”。从此以后,人们将计算机的错误统称为Bug。
Ron Patton给出了软件缺陷的经典定义,他认为,出于软件行业的原因,只有符合下列5条规则才能叫软件缺陷:
(1)软件测试员认为软件难以理解、不易使用、运行速度缓慢,或者最终用户认为不好。
从软件测试的标准定义可知,软件测试的最终目的是确保软件满足用户需求,因此,只要最终用户认为软件不好,当然对应到一个缺陷。另外,软件测试人员在一定程度上充当着用户的角色,如果连有着IT技术背景的测试人员都认为软件难以理解的话,用户恐怕就更难理解和使用该软件了。
举例:比如说手机,屏幕显示的数字过小,或者拨号键位置相对正常人操作而已过于不方便,都可以称的上是缺陷。
(2)软件未达到需求规格说明书(SRS)中指明的功能。(显性需求)
该规则对应的是遗漏缺陷,主要针对系统有效输入或有效操作下的功能的测试。用户最关心的往往是当其按照正确的流程、正确的操作输入正确的数据时,系统向其提供的功能能否达到用户所期望的结果。该规则的达成包含两方面的含义:
① 基本功能的保证,即应确保能实现有效输入下的基本功能;
② 性能的保证,即在保证提供基本功能之外,还能确保达到相关的性能指标。
举例:手机的产品说明书会声明可以接听、拨打电话。如果使用手机时,按下一个数字键“1”,结果什么反应也没有,按照第一条规则,这就是一个缺陷。如果,这次有了反应,但是…死机了,这也是一个缺陷。
(3)软件未达到需求规格说明书中虽未指出但应达到的目标。(隐形需求)
该规则是指,有些目标是说明书中没有明确指出,而实际上被测系统又应该达到的。那么,什么功能是需求中没提到,而被测系统又必须达到的?这部分功能主要是指软件系统对外部使用环境的要求,特别是对那些硬件故障所导致的意外情况的处理,如意外掉电等。此外还有软件的易用性、可靠性、可维护性、效率等。
举例:如某款手机电池电量低时,会发生拨号错误等问题,这也是不对的。需要考虑能让手机持续工作到电池完全没电,或者至少用到电力不足告警时。电力不足时无法正常工作,但是产品说明书中没有指出这个问题。这也是个缺陷。
(4)软件出现了需求规格说明书中指明不会出现的错误。
该规则是指若被测系统无法识别用户的无效输入或无效操作,并给予正确的反馈,则对应一个软件缺陷。该规则对应的是过错缺陷,主要针对系统无效输入或无效操作下的功能的测试。该规则的达成也包含两方面的含义:
① 系统能否应对所有可能的无效用户输入情况,包括无效输入数据和无效操作;
② 系统对每种无效输入情况,应以怎样的合理方式进行响应。
举例: 产品说明书也可能会声称手机不会锁死或者停止反应。但如果您是一个执着的人,不断按动键盘,手机停止接受数据了,这是一个缺陷。
(5)软件功能超出需求规格说明书中指明的范围。
该条规则看似很奇怪,既然是SRS中没有提到的功能,是属于不给钱的部分,开发人员为何会去实现呢?且软件要完成的功能越多,引入缺陷的风险越大,将带来更大的测试工作量并提高软件开发成本,这种吃力不讨好的事情,谁会主动去做?这里有两种可能性。
① 开发人员认为SRS不完善,因此而自行添加某些自认为用户需要的功能;
② 开发人员为了自己开发和调试的方便而加入的功能,如一些快捷键功能、测试代码等。
如果拿着手机进行测试,发现它除了接听电话、收发短信、上网、拍照以外,还可以充当扫描仪,而这一点没有在说明书中陈述,只是开发人员觉得它是一项很有用甚至了不起的功能而添加上的。这个也不叫功能,它是缺陷。软件实现了产品说明书中没有提到的功能,这些预料不到的操作,会增加测试的工作,甚至可能带来更多的缺陷。
软件缺陷产生的原因有很多,部分典型原因包括:
(1)软件及系统本身的复杂性不断增长,使得测试的范围和难度也随之增大;
(2)与用户的沟通不畅使得无法及时获取最真实的用户需求;
(3)需求不断变化,特别是敏捷开发模式下,测试开发和执行更难以跟上需求变化的步伐;
(4)程序员编程错误,或植入多余功能;
(5)进度压力导致测试被压缩,无法进行充分的测试;
(6)对文档的轻视致使测试缺乏依据,带来测试的漏洞。
实际上,在软件开发的各阶段均可能引入缺陷,并导致不同程度的损失,如图:
虽然软件缺陷(Defect)常被称为Bug,但二者又是有区别的。
(1)软件缺陷(defect)通常是指软件设计存在的问题。
(2)Bug通常是由软件缺陷(Defect)引起的一些软件故障,Bug是软件缺陷(Defect)的一种表现形式。
(3)一个缺陷是可以引起多种Bug的。
(4)绝大部分公司将计算机的错误统称为Bug
在介绍PIE模型之前,我们首先要介绍一些与缺陷相关的重要概念:
软件缺陷(Software Defect)
软件缺陷是存在于软件(文档、数据、程序)之中的那些不希望或不可接受的偏差,其结果是软件运行于某一特定条件时将出现软件故障,这时称软件缺陷被激活。“缺陷”被认为是“欠缺和不够完备的地方”。软件的欠缺和不完备主要是针对产品说明书而言的,它是静态的,如果不将其消除,它将永远存在。在业界,人们常用另外一个词“Bug”指代缺陷,这是从早期美国海军在调试软件时一个臭虫(bug)引发了系统不能正常工作的典故所流传下来的。将缺陷俗称为“Bug”,易使人对缺陷轻描淡写,忽视了缺陷的严重性,这是值得注意的问题。缺陷是造成软件故障乃至失效的内在原因。
软件故障(Fault)
软件故障是指在软件运行过程中出现的一种不希望或不可接受的内部状态。软件故障是一种状态行为,是指一个实体发生障碍和毛病。软件故障在ISO 14598软件产品评价标准中的定义是:计算机程序中不正确的步骤、过程和数据定义。一般是指在编写代码过程中出现的错误。“故障”指软件运行时丧失了在规定的限度内执行所需功能的能力,它是动态的,可能导致失效。故障不一定导致软件失效,软件运行可以出现故障但不出现失效,如在容错(Fault Tolerance)软件运行中容许有规定数量的故障出现而不导致失效。对无容错的软件,故障即失效。故障是软件缺陷的外在表现。
比如:我打算编写一个for i in range(3)的循环,当由于粗心,我写成了~~for i in range(2),
则这行写错的代码就被称为Fault。
软件错误(Error)
软件在运行过程当中,运行到fault就会产生一个相应的错误,触发到一个错误的中间状态。
比如:刚刚的例子中,我把代码写错成for i in range(2),则程序会比我预想中少执行一次循环。如果我想实现对 i 的累加,
并输出累加结果sum。正确情况应为sum=0+1+2=3,但我的代码存在Fault,
则会出现sum=0+1=1的情况。sum的这种计算错误就称为Error.
软件失效(Failure)
Error传播到软件外部,使用户观测到失效行为。称为失效行为,当Fault导致了Error,Error传播到外面,会导致预想之外的输出,这种错误为Failure。失效意味着系统是在运行,而且只有在执行程序过程中才会发生软件失效。
“失效”指软件运行时不能完成规定功能,它是动态的,由故障所导致。失效是软件缺陷的外在表现。
从上面的代码可以看出,当Fault :for i in range(3), 导致Error:s = 0+1, 代码运行,
会导致结果错误,sum的值表现在输出,与预期的结果3不一致,即为Failure。
软件测试的主要目的之一是发现缺陷。动态测试工作中通常会出现复杂而有趣的现象。假设某个程序中有一行代码存在缺陷,在该软件的某次运行中,这个存在缺陷的代码行并不一定会被执行。即使这存在缺陷的代码被执行,若没有达到某个特定条件,程序状态也不一定会出错。即只有在运行错误代码,并达到某个特定的条件,程序状态出错并传播出去被外部感知后,测试人员才能发现程序中的缺陷。
针对缺陷不同阶段的性质,我们可以构建一个PIE(Propagation-Infection-Execution)模型来解释缺陷产生的整体过程。PIE提示我们,发现一个缺陷需要满足以下三个必要条件:
1)Execution(运行):测试必须运行到包含缺陷(Falut)的程序代码。
2)Infection(感染):程序必须被感染出一个错误(Error)的中间状态。
3)Propagation(传播):错误的中间状态必须传播到外部并被观察到(Failure)。
PIE模型就是代码执行到Fault,感染产生Error,传播出去(输出),我们可以观测到Failure失效行为。这就是PIE模型。
结合Bug的定义, 用自己的话来描述一下PIE模型: PIE模型是存在Fault的代码被执行,触发了错误的中间状态Error,然后错误传播到软件外部, 成为用户和或测试人员能观测到的Failure的过程。
当然,Failure也不一定会被观测到,这时候会有三种情况:
也就是说,有Fault,不一定会感染Error; 又Error不一定会传播出Failure。
所以一个Bug 的发现我们在测试时要考虑尽可能多的可能错误的地方,去发现Failure 的产生。
PIE模型表明发现Bug并不是一件容易的事情。要全面发现软件Bug,不仅需要针对特定需求和软件特性进行测试设计,还需要学会利用不同的软件测试方法,如有效地结合使用白盒测试和黑盒测试方法。
随堂练习
设计一个程序,包含两个Fault(F1,F2), 同时构造test1, test2,和test3, 使得:
'''
设计一个程序,包含两个Fault(F1,F2), 同时构造test1, test2,和test3, 使得:
1. test1单独执行到F1,并且发现Failure
2. test2单独执行到F2, 并且发现Failure
3. test3同时执行到F1和F2,并且能对F1产生Error, 但没有Failure
'''
def MAX(a, b ,c):
if a == 0:
return 5 #Fault 1 ,逻辑错误, 产生对应Error
if b == 2:
return 2 ##Fault 2 ,逻辑错误,产生对应Error
max = b
if a > b:
max = a
if c > max:
max = c
return max
def test():
print('test1: oracle:2, output:', MAX(0,1,2))
print('test2: oracle:3, output:', MAX(1,2,3))
print('test3: oracle:5, output:', MAX(0,2,5))
def main():
test()
if __name__ == '__main__':
main()
>>>test1: oracle:2, output: 5 # 单独执行到F1,并且发现Failure
>>>test2: oracle:3, output: 2 # 单独执行到F2, 并且发现Failure
>>>test3: oracle:5, output: 5 # 同时执行到F1和F2,并且能对F1产生Error, 但没有Failure
软件缺陷类型、软件缺陷优先级、软件缺陷状态