zoukankan      html  css  js  c++  java
  • 软件测试的艺术(读书笔记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)该如何更早地发现错误?

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

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

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

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

  • 相关阅读:
    centos 安装 TortoiseSVN svn 客户端
    linux 定时任务 日志记录
    centos6.5 安装PHP7.0支持nginx
    linux root 用户 定时任务添加
    composer 一些使用说明
    laravel cookie写入
    laravel composer 安装指定版本以及基本的配置
    mysql 删除重复记录语句
    linux php redis 扩展安装
    linux php 安装 memcache 扩展
  • 原文地址:https://www.cnblogs.com/chengabc/p/11335893.html
Copyright © 2011-2022 走看看