仔细观察:第一件事情是要观察,观察你所做的一切操作和一切相关的系统反馈。在一开始,观察的重要性要远远大于思考,通过观察你获得蛛丝马迹,这些蛛丝马迹是你进行思考和假设的关键输入。例如,我在一次测试的过程中,发现做某种操作的时候会相当慢,极少数情况下还报错过一两次,当询问了开发人员后得知这个操作的后台实现步骤是:先查看数据是否在缓存中,如果不在,则从远端服务器请求数据。我抓住少数情况下会报错的这一现象,仔细观察它的出错信息后猜测报错并不是因为网络连接不稳定引起的,而是由于远端服务接口实现有问题引起的,后来重新设计了测试用例,果然找到了问题所在。如果不仔细观察出错信息,会听信开发人员认为这是网络不稳定引发的正常issue而错过这个bug。
  详细记录:详细记录你的操作步骤及返回结果非常有助于回朔问题,也有助于后续分析。准备一个word文档,和截图工具有时候非常必要。另外,在观察的时候,你不仅要注意被测物的终返回,还需要观察过程中的一些中间状态,往往这些中间状态提供的信息才是解开问题的关键。这些中间状态一般会被记录在log文件中,因此知道你的被测物是如何记log的,log被记录在哪里非常重要。log给了你另外一个看系统的角度。log是有级别的,如果级别可以动态调整,在找比较难找的bug时,可以将log记录的级别调至低(DEBUG级)让它们记录更多内容。利用系统的错误转储文件(比如linux的core dump文件,windows下也有相应的记录转储文件的方式)分析也是个不错的办法(需要较高技术能力),但一般建议测试人员把这些转储文件交给更专业的开发人员来分析。在我短暂的C++开发岁月中,有使用过GDB阅读转储文件的经历,那不是愉快的回忆。你瞧,测试人员的主要工作是找出可重现的bug,并不是定位它们,不是么?
  除了log,如果能有监控信息,也要查看他们。比如系统提供的监控平台,监控日志;应用自己的监控平台、监控日志(如果有的话);采用一些外部技术手段截取一些中间状态信息,如使用sniffer抓取通讯包,使用Fiddler截获HTTP报文内容;给运行程序插桩来查看内存,堆栈,线程,函数被调用情况等情况,如Jprofile,gpertool等等。
  科学分析:对于黑盒测试人员来说,科学分析意味着你需要有一定的分析策略。我们需要采取一些形式化的方法来完成我们的分析。基于我的统计,缺陷难以重现有很大一部分原因是因为“没有找到真正引发bug的操作序列“。测试人员不可能像开发人员那样去跟入到代码内部,设置断点调试程序,他们主要的测试方式是直接来操纵被测物,并从外部观察被测物状态的改变。显而易见,“状态转换图分析法”是测试人员对付“难以重现bug”的强有力武器之一。状态转化图能够帮助测试人员很好的选择操作路径,并且知道这么做有什么意义。“状态图转化法”是测试人员值得花时间学习和研究的一种方法,你可以走的很深,也可以研究得很远(可以从MBT的方向进行拓展),限于篇幅,这里不展开了。在这里推荐《探索吧!深入理解探索式软件测试》这本书,它的第八章对“状态转换”做了非常实用的描述。
  上文分析的让bug难于重现的另一种原因是没有找到“真正引发bug的特殊数据”。我的常用做法是这样的:1.画出系统交互图(要真正弄清系统的边界,这很重要),并识别出每种交互会有什么样的输入、输出数据和中间数据,识别出这些数据的规约和格式,这样你不会对数据有遗漏。2.考虑数据的等价类、边界值,对这些输入进行组合,分析数据之间是否有耦合关系,如果有耦合关系,弄明白关系是什么,设计违背这些关系的用例,后采用组合测试工具初步生成测试集,再人工选取可能出问题的数据集(直觉有时候非常管用)。
  严密推理:天马行空对测试人员很重要,但是当你试图重现一个bug的时候,这并不是一个非常好的方法。抓住了蛛丝马迹,你要推理是为什么产生了这种蛛丝马迹。限于工作性质,测试人员更多的会从:业务完整性、数据完整性、业务正确性、数据正确性等方面考虑问题。但是,如果测试人员对被测物的IT架构有比较深入了解的话,推理的范围会扩大到技术实现层面,如:多线程可能引发的问题,网络引发的问题,excepiton处理不当引发的问题,全局事务设计不当引发的问题,内存泄漏引发的问题,数据库表设计不合规引发的问题等等等等,这些会让你的分析推理能力如虎添翼。当然,如果限于条件,测试人员不具备这类能力,则应该在适当的时候请求开发人员协助。
  有序求证:这里只有一点需要注意。那是,在求证的过程中不要打散弹枪,按照你的推理一步一步的来,一个个推理的来验证,一次只引入一处修改。这样才能让你的捕虫网编制的足够细密。
  大胆假设:有的时候,看似八竿子打不着的东西竟然存在着千丝万缕的联系,而你获取信息的过程总是一个由少及多的过程,一开始这些联系是无法被识别出来的。通过推理,逐步验证,你慢慢的识别出了大部分内在联系。但有时候这种逐步推进的工作也会有局限性,工作如果出现了瓶颈(你试遍了你所有的假设,都没有重现bug),这时候需要发挥一点儿想象力了,天马行空这时候从一定程度上又变得有用起来,当然天马行空也不是无厘头,还得靠我们所谓的“灵光一闪”,这号称是潜意识在帮助你。CSI的剧情中不也总是出现这种柳暗花明的桥段么?
  坚持不懈:话不多说,有的时候你差的是那么一点儿点儿耐心。
  团队协作:很多情况下,重现bug不是一个人能搞定的。我们需要测试环境ready,测试数据ready,各种监控、分析工具ready,各种不同的视角开拓思路、加深对被测试物的认识。这是team work!!!独行侠有时候很管用,但是终究有极限。这是为什么CSI是一票人在做而不是一两个人在做。
  一点儿运气:说实在的,有的时候重现bug是靠运气,你不得不承认这一点。事实上很多美好的事情发生都得依靠运气,比如中彩票。要记住的一点是,运气是建立在你不懈努力的基础上的。如果你一张彩票不买,你肯定什么也中不了。但如果你坚持买上几年,中个五块十块甚至二百也不是梦。
  Let it go:全试过了,连运气都没有。你只能放手,回到上面我说的那两条了:找开发来帮忙,或者给开发报issue。btw,即使不能重现bug,也应该给开发人员提供更多信息:如log、dump文件、监控记录、屏幕截图等。做一个负责人的测试人员,把烦恼真实的留给下家,这很重要。