软件测试的艺术(读书笔记6)


下面开始本书第四部分的读书笔记部分

第四部分 开发中的调试和测试思想

  第8章 调试;第9章 极限测试思想

第8章 调试

  调试是执行一次成功的测试(发现软件中的错误)之后所要进行的工作。也就是说如果程序测试中发现了问题,就需要程序员对程序进行调试来解决问题。调试包括两个部分:定位问题和修改错误。测试到调试的关系图如下所示

    

  因为对错误进行定位可能就已经解决大部分的问题,所以本章着重讨论定位错误的几种方法;然后,通过本章总结的一些调试原则,告诉读者最有效的调试方法,是在调试时进行“思考!”,只有这样才能高效的调试和解决问题;最后,作者告诉读者,光会调试还是不够的,还需要对错误进行分析,进而获取改进设计和测试过程的有价值信息。

  1、暴力法调试

    此方法很流行,我调试程序也经常用这类方法,因为它不需要过多思考,不费脑子,但是效率低下。只有在其他方法都失败或者作为替代方法进行调试。

    1)利用内存信息输出来调试

      如果做嵌入式设备,因为地址中内容是16进制数据,可能会查看Flash地址中的内容,来调试程序。但这种方法极其低效。

    2)在程序中插入打印语句来调试

      如果是嵌入式设备,可能还会添加亮灯、蜂鸣或串口打印等方式;

      如果是小型应用程序,可以将每次产生的数据通过日志形式输出,根据日志内容来确定问题,分析问题和解决问题;

      但是对大型程序,如操作系统、过程控制软件,就很难应用。

    3)自动化调试工具

      使用编程语言的调试功能,类似于在程序中插入打印语句,只是不修改程序本身。

      比如Visual StudioIDE、Keil MDK等集成开发环境,通过设置断点、跟程序进行调试。

  2、归纳法调试

    从名字可以看出,归纳法其实是一种思考的过程,是一种从特殊到一般,从线索(错误的现象,或测试用例的结果)出发,找出线索之间联系,进而解决问题。

    有如下5个步骤:1.确定相关数据;2.组织数据;3.作出假设;4.证明假设;5.解决问题。

   

 

    1) 确定相关数据

      将所有可能的数据或现象均考虑进去,正确和不正确的数据和现象都需要得到;

    2)组织(解析)获取的数据

      通过组织相关数据,以便观察数据之间的关系,进而对数据进行解析,解析数据的方法可以按照,“是什么”、“在何处”,“在何时”,“多大程度”进行分析。

      “是什么”,对症状或现象的描述;“在何处”,描述这些症状出现的位置;“在何时”,描述这些症状什么时候发生;“多大程度”,描述这些症状的范围和重要性;注意“是”,“否”列,描述的矛盾之处最终可能会导致对错误的假设。

是什么 测试用例3中显示中间值不正确  
在何处 仅在测试用例3中出现 学生成绩计算似乎正确
何时 当测试学生数量为51时发生 测试学生数量为2或200时未发生
多大程度 显示的中间值为26。当学生数量为1时也同样发生,显示的中间值为1  

    3)做出假设

      这时候需要研究线索之间的联系,假设一下产生错误的原因,如果找不出来,则需要更多数据;

    4)证明假设

      将假设同最初的线索或数据进行比较,看看假设是否具有合理性,如果假设无效,则需要重新构造假设,或需要更多数据;

    5)解决问题

      完成前面几步后,则可以修复这个问题。有一条需要记住:做回归测试,确保修复错误的同时没有引入其他新的错误。

  3、演绎法调试

    演绎法:是从一般理论或前提出发,使用排除法,提炼剩余的假设,进而达到结论(错误的位置)。

    与归纳法正好相反,演绎法是先找出所有可能的原因或假设,然后排除不可能的原因或假设,最后剩下的那个原因可能就是最终的结论。

    演绎法调试有以下几个步骤:1.找出所有可能的原因或假设;2.排除不可能的原因或假设;3.提炼剩下的假设;4.证明剩下的假设;5.修改错误(解决问题)。

    

  

    1)列举出所有可能的原因或假设

      当收集到有问题的数据时,需要先列出数据出现问题的原因或假设的列表(仅仅是猜测)。

    2)利用数据排除掉不可能的原因

      利用归纳法调试中解析数据的方法(是什么,在哪里,在何时,多大程度上)排除掉不可能的原因,剩下的原因可能就是真正的原因。当所有原因都排除掉了,需要设计新的测试用例。

    3)提炼剩下的假设

      剩下的假设也许是正确的,但是不够具体,可以根据当前有的线索,将假设具体化。

    4)证明剩下的假设

      将假设同最初的线索或数据进行比较,看看假设是否具有合理性,如果假设无效,则需要重新构造假设,或需要更多数据;

    5)修改错误(解决问题)

      完成前面几步后,则可以修复这个问题,有一定需要记住:做回归测试,确保修复的错误没有引入其他新的错误。         

  4、回溯法调试

    此方法一般用在小型程序中进行错误定位。

    当发现错误后,可以从出现错误的位置开始,开始逆向执行程序,直到找出程序逻辑出错的位置。

    重复使用“如果程序在此处的状态是这样,那么程序在上面的位置的状态就必然是那样的”过程,可以很快定位错误。

  5、测试法调试

    两种测试用例:供测试用的测试用例;供调试用的测试用例。

    供测试用的测试用例:目的是暴露出以前尚未发现的错误,涵盖的条件较多;供调试用的测试用例:目的是提供有用信息,供定位某个被怀疑的错误之用,涵盖的条件较少。

    当发现某个测试用例发现了错误,需要编写与原先有变化的(瘦身的)测试用例,尽量确定错误的位置。

    工作中这种方法也可以叫做:复现问题,通过设计一种与原来的测试用例相似的用例,让错误再次发生。

    结合归纳法使用,获得进行或证明假设的信息;结合演绎法使用,排除有嫌疑的原因,提炼剩下的假设,并证明假设。

  6、调试的原则

    调试原则,实质上也是心理学的原则。调试过程分定位错误和修改错误。

    6.1 定位错误原则

    1)动脑筋

    调试是一个解决问题的过程,最有效的调试方法是动脑筋对错误症状的有关信息进行分析,以下列出一些思考的诀窍。

      • 让自己置身于安静、没有干扰的环境中
      • 不看代码,在脑海中思考程序是怎么设计,并思考表现异常的地方本该是什么样的
      • 将注意力集中在思考程序正确行为的过程上,并想象那些可能导致错误设计的代码实现方式

    2)如果遇到了僵局,就留到稍后解决

    如果在合理时间内(小程序30分钟,大程序1个小时),还不能定位问题,就离开它,做些其他的事情。

    忘记这个问题一段时间后,再重新检查问题的症状,思维会焕然一新。

    不仅调试,开发过程也可以这样。

    3)如果遇到了困境,就把问题描述给其他人听

    与其他人交谈可能会帮助我们发现一些新的东西。

    仅仅将问题描述给倾听者,而无须倾听者提供任何帮助,就会突然找到问题的解决之道。

    4)仅将调试工具作为第二中手段

    在试过其他方法后才是用调试工具。

    将调试工具作为头脑思考的辅助手段,而不是替代手段。因为对工具的过分依赖,可能减少对已经获得的线索的关注,可能这些线索就能帮你直接解决问题。

    5)避免使用试验法--仅将其作为最后的手段

    不要为了调试程序而去试验性地去修改程序。

    6.2 修改错误的技术

    1)存在一个缺陷的地方,很有可能还存在其他缺陷

      因为错误有扎堆出现的倾向。在修改某个问题的同时,应检查一下紧邻的地方,看看有没有可能是错误之处。

    2)应纠正错误本身,而不仅是其症状

      应从根本上解决问题,而不应该只修改错误的一部分。

    3)正确纠正错误的可能性并非100%

      应对错误的修改进行测试,也许比对原先程序的测试还要严格(回归测试)。

    4)随着程序规模的增加,正确修改错误的可能性反而降低

      经验:由于修改不正确而引入的错误与原始错误之比,在规模较大的程序中呈递增趋势。对于广泛使用的大程序,每发现6个新错误,就有1个错误是由于先前对程序的改正而造成的。

    5)应意识改正错误会引入新错误的可能性

      对错误的修改点进行测试,同时应执行回归测试。

    6)修改错误的过程也是临时回到设计阶段的过程

      在设计阶段使用的任何规程、方法和形式都同样适用于错误修改阶段。例如,项目证明代码检查很管用,那么在修改错误之后进行代码检查就显得倍加重要。

  7、错误分析

  调试除了消灭程序中的错误,还告诉我们软件错误的本质,这些软件错误本质的信息可以为改进将来的设计、编码和测试过程提供有价值的反馈。

  通过详细分析发现的错误,可以获得关于软件有价值的信息,详细的错误分析包括:

  1)错误出现在什么地方?

    通过对程序文档和项目历史进行追溯,找到该错误的源头和发生时间。

    比如,错误源头可能是:1.规格说明书中模棱两可语句;2.对上次错误的修改;3.对最终用户需求的错误理解。

  2)谁制造了这个错误?

    如果30%的错误都是某个程序员产生,不是很有用吗?(不是为了惩罚,而是为了进行培训)

  3)哪些做得不正确?

    需要判断错误发生的原因。比如,1.错误是由于某人写得不清楚;2.错误是由于某人缺乏对编程语言的培训;3.错误是打字错误;4.错误假设做得不对;5.错误是没有考虑有效输入;

  4)如何避免该错误的出现?

    在下一个项目中应如何避免该问题的出现?(这就是最宝贵的经验和信息)

  5)为什么错误没有早些发现?

    如果错误是在测试阶段发现的,需要研究:为什么更早的测试阶段、代码审查和设计阶段中没有发现错误。

  6)该如何更早地发现错误?

    如何改进评审和测试过程,以便在将来的项目中更早发现同类型的错误。

  通过对错误进行分析,可以积攒开发和测试的经验,保证质量的同时节省开发和维护的成本。

  综上,本章首先介绍了一些软件调试的方法,包括暴力法调试、归纳法调试、演绎法调试、回溯法调试和测试法调试;然后,介绍一些定位错误和修改错误的技术原则,帮助读者更快速和更高效的进行调试;最后,作者介绍一些对错误进行分析的方法,为将来改进软件质量提供有价值的信息。

  发现在工作中这些调试方法都会使用,只是没有像书中那样汇总的那么全面;同时工作中使用最多的也还是暴力调试法,如果想获得提升和进步,还是需要使用一些需要引发自己思考的方法(归纳法和演绎法等),不过这一切的基础都是构建在自己对程序本身的了解和掌握上(程序还是要认真的看滴,不要认为测试就不要看程序)。

 


作者:chengabc,发布于:2019/08/14
原文:https://www.cnblogs.com/chengabc/p/11335893.html