第2章 找Bug的核心思维与境界
通过找Bug来推动软件质量的提高,是软件测试最基本的目的。围绕着Bug,本章首先介绍逆向思维与发散思维在找Bug中发挥的价值,接着介绍测试的三重境界,对不同境界的理解,会有不同的行为结果。第一重境界:围着Bug转。通过发现Bug,协助开发人员分析问题,定位问题,最后解决了Bug,才能对质量有实质的贡献。第二重境界:站在Bug之上。我们完全可以跳出测试软件的小圈子,拓宽测试的视野。测试的价值不仅仅是发现Bug,它服务于整个产品的开发链,项目的成功可以带来测试的成功。第三重境界:挑战零缺陷。Bug是设计出来的,它从来不会自生自灭。追求零缺陷,以预防为主,事后的测试验证为辅,主动推动设计尽量一次做好,这是测试的最高境界。通过测试三重境界的介绍,读者可以对测试的价值有更全面、更合理的理解与认识。
2.1 情有独钟的思维模式
测试思维模式各种各样,如大家常用的逆向思维、组合思维、发散性思维、比较思维等,其中“逆向思维”与“发散性思维”是重中之重,对测试的质量与效率有着重要的影响。
2.1.1 逆向思维
在软件研发办公室里,常会看到这样的场景(如图2-1所示),测试工程师发现了一个严重的Bug,笑呵呵地找负责此模块的开发工程师来看现场,以确认Bug的存在并且做现场分析,而开发工程师却是一副神情紧张、半信半疑的样子,即便确认是一个Bug后,还不相信别人也不相信自己,止不住地说“这怎么可能呢?我看看代码再说”。读者朋友们,这是为什么呢?
图2-1 测试与开发之间的Bug List传递场景示意图
在笔者接触过的开发工程师中,曾经有不少人提到过同样一个问题:“他们辛辛苦苦、日夜奋战编写代码,设计出来的软件就像是他们的孩子,对它们有着一种特殊的感情。特别是在大型项目中,经过几十万行,甚至上百万行代码编写的历练后,最后要离开这个项目,与这些曾经日夜为伴的代码说再见时,总有那么一种恋恋不舍的感觉”。从心理学的角度看,这也是符合人的正常心理的,谁愿意自己生产的是一个多病的“孩子”呢?但现实却很残酷,谁家的“孩子”会没有生过病呢?笔者曾经遇到过很多次这样的情况,测试提交Bug后,与负责的开发工程师交流,然而开发工程师却诡异地笑道“啊!此Bug终于被你们发现了,我还以为你们发现不了呢。”当时真不理解,怎么会有这种事情发生,看到代码中存在的Bug,却不主动去改。现在回想起来,是现实与心理的种种原因的驱使吧,毕竟任何一个Bug的修改与否都存在风险。
在业界,也有人形象地比喻说,开发是盖房子,测试是拆房子,这种看法或许存在某些偏见。实际上开发也好,测试也罢,大家的目标是一样的,都是为设计出满足用户需求的高质量的软件。只是由于分工不同,开发与测试在工作的性质上天生成了对立面。开发的工作是要把需求实现,而测试是验证开发的实现是否满足需求,这种验证本身是带着一种怀疑的眼光和不信任的姿态,这也造就了测试工作本质上就需要有与开发不一样的逆向思维。事实证明,这种思维越强烈越能发现问题。测试的目的是发现Bug,证明程序有错,要证明程序有错就需要有说服力的数据,而这些有说服力的数据就是Bug。如果仅从正向思维出发,设计的测试用例自然也是正向的,这与开发人员进行设计实现时走的是同样的路,即验证程序是按需求实现了,能达到预期,但实现了的产品是否存在问题,不得而知。正向思维思考与逆向思维思考,仅是一字或一念之差,结果却大不一样。
逆向思维的方法,笔者通常把它理解为“不走寻常路”,这也是程序员常忽视的地方。
如图2-2所示是一个场景示意图。小红每天从家(S点)出发到学校(C点)上课,通常情况下,她的路线是S→O→C,但是她也可以走到一棵树(O点)时回头返回S点,然后再往回走或选择其他路线到学校,如S→O→S→O→C,或者是S→O→S→D→O→C等。当然,实际生活中进行这种路线走法的人可能并不多(让人感觉有点不正常),但它确实也是一种数学上的拓扑路线。这种不寻常的路线可以看做是软件业务中实现某种功能的特殊路径,常常潜伏得较深的Bug就是需要这种迂回曲折的路径后才能暴露出来。这种路径如何有意识地执行,须对测试对象进行深入分析。
图2-2 “不走寻常路”场景示意图
下面结合实际的软件测试应用场景进行讲解。
【案例】
某手机通信录列表显示界面如图2-3所示。通信录列表用来显示用户的通信信息,包括姓名、电话号码等。界面图标工具栏上有“删除”按钮(图中画线标识),用于删除记录。就“删除”记录的功能来说,正常情况下,选择一条记录后,单击“删除”按钮,记录即可被删除。但是曾经遇到过这样的Bug:列表中只有一条记录,删除此条记录后,再单击“删除”按钮,手机屏幕突然黑屏,程序crash(崩溃)。后来查明是按钮的状态不对,当列表中没有记录的时候,删除按钮仍在激活状态。记录删除了(列表已为空),为什么还要去单击“删除”按钮呢?难道测试人员真是没事干?而这恰恰是测试用例设计“不走寻常路”的逆向思维的体现。
图2-3 通信录界面示意图
不走寻常路,大家都是这样走,我却往反方向走,用与正向思维相反的思维方式设计用例,挖掘新Bug。这是一种历练,也是历练中的摸索、创新。通过这种不同寻常的历练,常能让我们总结出自己的方法,并且在测试方法上不断得到扩展,有助于我们成长。
小贴士:
用不走寻常路的“逆向思维”设计用例,关键点在于找准测试对象的反面。
2.1.2 发散性思维
发散性思维是一种探求多种答案,最终使问题获得圆满解决的思维方法。由于其视野开阔,思维活跃,可以产生出大量独特的新思想。著名的心理学家吉尔福特指出:“人的创造力主要依靠发散性思维,它是创造思维的主要部分”。正如其本身的特点所言,发散性思维在软件测试工作中的应用,从发现的问题来看,很有创意,是一种很好的思维方法和测试方法。
概括来说,发散性思维在测试过程中可在以下两个阶段得到充分体现。
第一:测试设计阶段的发散。
它也可理解为测试方案,即测试思路的形成阶段。下面以大家日常工作、生活中经常见到的场景为例,介绍发散性思维在软测中的应用。
【案例】
某公司在招聘测试工程师时,有一道这样的笔试题:“某嵌入式软件有用U盘导出数据的功能,请写出测试此功能点的思路”(读者朋友,在往下看之前,建议先做做看)。
下面给出测试此功能点的测试思路,如表2-1所示。此表并非标准答案,旨在说明围绕一个测试对象,如何运用发散性思维进行思考。
表2-1 发散性思维设计测试用例
第二:用例执行阶段的发散。
我们都知道,用例执行时须严格按事先已设计好的用例来测试,但由于在实际工作中,软件测试不能进行穷举测试,用例对代码的覆盖率做不到100%,特别是对一些条件组合语句、模块接口相互影响之间的覆盖,更难覆盖全面。根据这一特点,在测试执行完某一测试点的用例后,可以根据已有用例的情况,进行发散性测试,这种发散性测试,也叫随机测试。测试者经验越丰富,随机测试的效果越好。但这种随机测试并不是随便测试,它是有一定依据支持执行的。
或许,我们可以这样理解,对某一条已有的用例进行分解,即不完全按事先设计好的操作步骤进行,或走了一步或两步后,跳出既定的步骤提前结束,结果往往能发现问题。跳出既定的步骤,可以回头张望,可以疾步跳跃,可以反反复复做某个动作,这种思维发散的过程,本身就是一种用例设计的过程,如图2-4所示。这个过程就好像是我们的思维与已设计好的软件在玩一种游戏,是一种试探性的对抗。这种玩法,常能出乎程序员的意料,发现一些特殊情况下才能发生的问题。
图2-4 用例执行发散示意图
除了发散,我们还需严谨。这种发散思维,如果无边无垠,任其驰骋,就像一匹野马,如果控制不住,事情会弄巧成拙,可能做了很多工作,到最后却事倍功半。这也就要求我们既要有发散测试的创造性思维,又要有一个严谨科学工作的头脑。
下面对用例执行过程中的发散思维示意图进行解释。
图2-4中数字表示操作步骤,1.1表示由步骤1扩展出来的分支步骤,依此类推,2.1、2.2、3.1的意思类似。
正常主操作流程用例:Start-1-2-3-4-End。
发散用例1:Start-1-1.1-End,从步骤1中分支出来到结束,有走路时抄小路的味道。
发散用例2:Start-1-2-3-3.1,此用例不能到流程结束,即不能完成某一有意义的功能,但测试时可以进行探索。正常情况下,它可以回到步骤3,如果进行到3.1,软件不能进退,说明设计上存在缺陷。
发散用例3:Start-1-2<->2.1<->2.2,步骤2与扩展步骤2.1、2.2之间反反复复来回执行,如图2-4所示的虚框。