软件调试软件测试什么是软件调试?•软件调试的原因?•什么是软件调试?•软件调试的特点•调试步骤•调试的主要难点DEBUG的由来1937年,美国青年霍德华.艾肯找到IBM公司为其投资200万美元研制计算机,第一台成品艾肯把它取名为:马克1号(mark1)为马克1号编制程序的是哈佛的一位女数学家格蕾丝·莫雷·霍波,有一天,她在调试程序时出现故障,拆开继电器后,发现有只飞蛾被夹扁在触点中间,从而“卡”住了机器的运行霍波诙谐的把程序故障统称为“臭虫(BUG)”,把排除程序故障叫DEBUG软件调试的原因?任何一个天才都不敢说,他编的程序是完全正确的。几乎每一个稍微复杂一点的程序都必须经过反复的调试,修改,最终才完成。所以说,程序的调试是编程中的一项重要技术。在应用程序中发现并排除错误的过程叫做调试。软件调试什么是调试(Debug)?•软件调试是在进行了成功的测试之后才开始的工作。它与软件测试不同,调试的任务是进一步诊断和改正程序中潜在的错误。•调试活动由两部分组成:–确定程序中可疑错误的确切性质和位置。–对程序(设计,编码)进行修改,排除这个错误。•调试工作是一个具有很强技巧性的工作。•软件运行失效或出现问题,往往只是潜在错误的外部表现,而外部表现与内在原因之间常常没有明显的联系。如果要找出真正的原因,排除潜在的错误,不是一件易事。•可以说,调试是通过现象,找出原因的一个思维分析的过程。调试的特点:调试——一项最不受欢迎的活动•个人自尊会从中阻挠•热情耗尽•可能迷失方向•必须自力更生调试的步骤(1)从错误的外部表现形式入手,确定程序中出错位置;(2)研究有关部分的程序,找出错误的内在原因;(3)修改设计和代码,以排除这个错误;(4)重复进行暴露了这个错误的原始测试或某些有关测试。•现象与原因所处的位置可能相距甚远。•当其它错误得到纠正时,这一错误所表现出的现象可能会暂时消失,但并未实际排除。•现象实际上是由一些非错误原因(例如,舍入不精确)引起的。•现象可能是由于一些不容易发现的人为错误引起的。调试的主要难点——技术上•错误是由于时序问题引起的,与处理过程无关。•现象是由于难于精确再现的输入状态(例如,实时应用中输入顺序不确定)引起。•现象可能是周期出现的。在软、硬件结合的嵌入式系统中常常遇到。调试的主要难点——技术上磨刀不误砍柴功•熟悉当前的开发(调试)环境,比如:设置断点、单步运行、全速运行、终止运行,查看RAM、查看堆栈、查看IO口状态……总之,要熟练掌握基本操作的方法,并深刻了解其中意义。•了解软件本身的可用资源和特性。•了解操作系统和一些硬件资源的知识。•掌握基本的调试技巧和常用的调试工具。•搜索、鉴别资料的能力。(内事问百度、外事问谷歌)•与人沟通,描述问题的能力。(调试36计的最后一计——就是向他人讨教。尤其是我们现在可以直接询问一些技术支持,这使得我们解决问题更加便捷。当然,你得把话说明白才行)•……•差不多了,如果上述6把砍柴刀磨好了,就可以开始调试了。接下来,请调试你的程序……软件常见的错误类型•语法错误•编译错误•运行错误•逻辑错误1语法错误•词法错误和句法错误。•例如:前边有{,后边缺少}•参数该是整型的变量用了字符型•……2编译错误•编译错误是指程序在编译过程中出现的错误。它是由于不正确的编写代码而产生的如非法使用或丢失关键字、遗漏了某些必需的标点符号、函数调用缺少参数或传递了不匹配的参数等等。•例:fore(inti=0;i100;i++)//关键字书写错误{}编译错误3运行时错误•运行时错误是指应用程序在运行期间执行了非法操作或某些操作失败,如打开的文件未找到、磁盘空间不足、网络连接断开、除法中除数为零等等;•例:数组下标越界是一种典型的运行时错误。int[]arrayX=newint[4];for(inti=0;i5;i++){arrayX[i]=i;}运行时错误运行时错误4逻辑错误•逻辑错误是指应用程序未按照预期的方式运行时所产生的错误。一般来讲,这不是属于语法层次的错误,应用程序可以执行,但是得不到正确的预期结果。•例:对于一个数组的初始化,预期对其某个特定位置赋初始值,其余置零:int[]array=newint[100];array[55]=55;for(inti=0;i100;i++)array[i]=0;那么在这段代码完成后就没有得到我们预期的结果(代码执行顺序的逻辑错误)。调试的类别•调试方法分为两种:动态调试和静态调试。•程序的静态调试就是在程序编写完以后,由人工“代替”“模拟”计算机,对程序进行仔细检查,主要检查程序中的语法规则和逻辑结构的正确性。实践表明,有很大一部分错误可以通过静态检查来发现。通过静态调试,可以大大缩短上机调试的时间,提高上机的效率。调试的分类•程序的动态调试就是实际上机调试,它贯穿在编译、连接和运行的整个过程中。根据程序编译、连接和运行时计算机给出的错误信息进行程序调试,这是程序调试中最常用的方法,也是最初步的动态调试。在此基础上,通过“分段隔离”、“设置断点”、“跟踪打印”进行程序的调试。几种主要的调试方法•暴力法调试•归纳法•演绎法•回溯法•测试法应用以上任一种方法之前,都应当对错误的征兆进行全面彻底的分析,得出对出错位置及错误性质的推测,再使用一种适当的调试方法来检验推测的正确性。这种调试方法目前使用较多,效率较低。它不需要过多的思考,比较省脑筋。例如:–通过内存全部打印来调试,在这大量的数据中寻找出错的位置。–在程序特定部位设置打印语句,把打印语句插在出错的源程序的各个关键变量改变部位、重要分支部位、子程序调用部位,跟踪程序的执行,监视重要变量的变化。–自动调试工具。利用某些程序语言的调试功能或专门的交互式调试工具,分析程序的动态过程,而不必修改程序。强行排错•难以在内存区域与变量之间建立对应关系•内存信息数量庞大,大多数与调试无关•内存信息输出是静态快照,是某一刻的状态,需要的是跟踪动态状态•内存信息很少可以精确地在错误发生地方产生•通过分析输出的内存信息发现问题的办法不多第一种类型•它不是鼓励我们思考程序中的问题,而主要是一种碰运气的方法•它所产生的需要分析的数据量非常庞大•它要求我们修改程序,这些修改可能会掩盖掉错误,改变关键时序关系,或者会引入新错误•它可能对小程序有效,大型程序成本相当高,而且对于一些类型的程序,甚至无法使用.第二种类型•类似于在程序中插入打印语句,但不修改程序•可以使用编程语言的调试功能•特点是可设置断点…•也需要碰运气,会产生大量的无关数据第三种类型•忽略了思考的过程•调试程序和侦破谋杀案有相似处•谜案都是通过仔细分析线索,将表面不重要的线索联系起来,这不是一个使用蛮力的方法暴力调试主要问题•其他方法都失败了•其他方法的补充,而不是替代暴力调试的使用时机•这是在小程序中常用的一种有效的调试方法。一旦发现了错误,人们先分析错误征兆,确定最先发现“症状”的位置。然后,人工沿程序的控制流程,向回追踪源程序代码,直到找到错误根源或确定错误产生的范围。•例如,程序中发现错误处是某个打印语句。通过输出值可推断程序在这一点上变量的值。再从这一点出发,回溯程序的执行过程,反复考虑:“如果程序在这一点上的状态(变量的值)是这样,那么程序在上一点的状态一定是这样...”,直到找到错误的位置。回溯法调试•归纳法是一种从特殊推断一般的系统化思考方法。•归纳法调试的基本思想是:从一些线索(错误征兆)着手,通过分析它们之间的关系来找出错误。归纳法调试–收集有关的数据列出所有已知的测试用例和程序执行结果。看哪些输入数据的运行结果是正确的,哪些输入数据的运行结果有错误。–组织数据由于归纳法是从特殊到一般的推断过程,所以需要组织整理数据,以发现规律。常以3W1H形式组织可用的数据:“What”列出一般现象;“Where”说明发现现象的地点;“When”列出现象发生时所有已知情况;“How”说明现象的范围和量级;“Yes”描述出现错误的3W1H;“No”作为比较,描述了没有错误的3W1H。通过分析找出矛盾来。–提出假设分析线索之间的关系,利用在线索结构中观察到的矛盾现象,设计一个或多个关于出错原因的假设。如果一个假设也提不出来,归纳过程就需要收集更多的数据。此时,应当再设计与执行一些测试用例,以获得更多的数据。–证明假设把假设与原始线索或数据进行比较,若它能完全解释一切现象,则假设得到证明;否则,就认为假设不合理,或不完全,或是存在多个错误,以致只能消除部分错误。•演绎法是一种从一般原理或前提出发,经过排除和精化的过程来推导出结论的思考方法。•演绎法排错是测试人员首先根据已有的测试用例,设想及枚举出所有可能出错的原因做为假设;然后再用原始测试数据或新的测试,从中逐个排除不可能正确的假设;最后,再用测试数据验证余下的假设确是出错的原因。演绎法调试–列举所有可能出错原因的假设把所有可能的错误原因列成表。通过它们,可以组织、分析现有数据。–利用已有的测试数据,排除不正确的假设仔细分析已有的数据,寻找矛盾,力求排除前一步列出所有原因。如果所有原因都被排除了,则需要补充一些数据(测试用例),以建立新的假设。–改进余下的假设利用已知的线索,进一步改进余下的假设,使之更具体化,以便可以精确地确定出错位置。–证明余下的假设•使用测试用例。供调试的测试用例,目的是提供有用的信息,定位某个被怀疑的错误•当发现缺陷的症状后,会编写供调试的测试用例,发现错误位置•不是一种独立的方法,常结合归纳法或演绎法一起使用测试法调试调试原则•在调试方面,许多原则本质上是心理学方面的问题。调试由两部分组成,调试原则也分成两组。•用头脑去分析思考与错误征兆有关的信息,避开死胡同。•如果遇到僵局,就留在稍后解决。•遇到困难,就把问题描述给别人听。•只把调试工具当做辅助手段来使用。利用调试工具,可以帮助思考,但不能代替思考。•避免用试探法,最多只能把它当做最后手段。确定错误的性质和位置的原则•在出现错误的地方,很可能还有别的错误。•应纠正错误本省,而不是症状。•正确纠正错误的可能性并非100%•正确修改错误的可能性随着程序的规模增加而降低•当心修正一个错误的同时有可能会引入新的错误。•修改错误的过程将迫使人们暂时回到程序设计阶段。•修改源代码程序,不要改变目标代码。修改错误的原则错误分析•错误出现在什么地方?•谁制造了这个错误?•那些做的不正确?•如何避免该错误的出现?•为什么错误没有及早发现?•该如何更早的发现错误?调试技巧•指表现在艺术、工艺、体育等方面的巧妙的技能。•为什么要先调显示模块?道理很简单,我们说“眼睛是心灵的窗户”,同样,“显示是程序的窗户”。一旦把显示模块调试好了,就可以通过这个窗口,观察程序内部的数据和状态了。优先调试人机界面•如何实现这个慢镜头呢?方法很多:1、单步运行2、在每一步分动作之后设立断点3、在每一步分动作之后插入足够的延时,让我们可以看清楚这些分动作•通过慢镜头的反复回放,我们就可以发现,到底是哪一个分动作出现了问题。•只要一个功能可以被细分为若干的动作,那么这一招“慢镜头分解法”都是可以使用的。慢镜头的威力•我们可以在不同的分支路口,或者在我们怀疑的地方,设立断点,看程序是否走了不该经过的路径。•举个例子,比如程序中某个环节有A、B两个分支,正常时只走A分支,不正常时才走B分支。那么我们可以在B分支设立断点,程序一旦异常,走入B分支,就可以被拦截下来。•程序被拦截下来后,我们可以勘察现场,查看程序刚走过的路径,从中分析导致程序错乱的原因。•当然,并不是每一次伏击守候都能找到问题所在。这就需要我们多一份耐心和技巧。通过不断调整断点位置来改变拦截地点。逐渐逼近并找到根源,然后进行正确修改。在程序中设卡伏击•有意的布置错误代码向猎人学习挖坑设陷阱的技术在程序中设置窃听器•中间结果的输出•看看电脑修理工是怎么干活的:面对一台故障不明的电脑,修理工会把先不相关的部件拆掉,只留下电源、主板、CPU三样基本核心部件,看能否启动;如果这一步通过了,他们