难以重现的 Bug如何处理
对很多测试人员(尤其是对新手来说)在工作过程中最不愿遇到的一件事情就是:在测试过
程中发现了一个问题,觉得是 bug,再试的时候又正常了。
碰到这样的事情,职业素养和测试人员长期养成的死磕的习性会让她们觉得不能放过这个
bug,但是重现这样的 bug 有时候需要花费大量的时间,有的时候还有一些盲目性(因为黑
盒测试的缘故,很多内部状态是不可见的,因此无法获取有效的信息来做跟踪),效率较为
低下。
在实际工作中,时间和进度摆在那里,在经历了多次痛苦的失败尝试之后,测试人员的处理
方法一般会有如下几种:
1.向开发人员寻求帮助来重现 bug;
2.当做一个 issue 报给开发人员。
可是这样的做法存在如下问题:
1.开发人员责任心不够强,不愿意花太多精力去求证这件事情,常见的回复就是:在我这儿
没事儿啊,我也重现不了,bug 关了吧。结果随后在生产系统上,bug 又开始随机出现了。
2.就跟测试人员不擅长编码和调试一样,开发人员并不擅长找出 bug。经过一番尝试以后,
他们也找不出什么问题来,常见的回复同第一条是一样的。bug 上线后又出现的宿命也是一
样的。
这时候,真正的问题来了:如何捕捉难以重现的 bug?这件事儿对于测试人员来说就这么难
么?
答案并不那么乐观,重现“难以”重现的 bug 本来就是一件“难以”完成的事情。但“难以”并不
是不可能,通过一系列的测试、分析方法,我们是能够抽丝剥茧把绝大部分隐藏的很深的
bug 揪出来的,当然有的时候你要考虑投入产出比,但投入产出比不是本篇要考虑的,本篇
只讲一些我积累的经验。
为什么不能重现 bug?
最大的原因就是:测试人员对被测物的了解还不够深入。
我曾经做过一段很长时间的收集和统计,那些被称作过“难以重现”的 bug 最后都可以分为如
下几类:
1.环境的变更造成了 bug 难以重现,这里的环境包括了:基础软硬件环境(操作系统、网络、
存储、中间件、容器等等),被测物自身发生了某些变更。环境的变更一般是由于多人共用
环境造成的,也有少量情况下是系统内部或者时间触发的变更(这类 bug 非常难重现)。
2.没有找到真正引发 bug 的操作。这些操作往往是一些不怎么显而易见的操作,测试人员在
不经意间完成,而又忽略了这一操作,以致难于重现 bug。
3.没有找到真正会引发 bug 的操作序列。很多 bug 的重现需要满足多个条件。在满足多个条
件的状态下,你做了对应的操作,bug 才会被触发。
4.Bug 必须使用特殊的数据才会出现,测试人员没有意识到她使用的数据的特殊性。一种比
较难搞的情况是:同一组输入,在不同情况下(不是不同的业务情况)输入会被转化成不同
的数据。我曾经见到过这么个例子,程序员用系统当前时间作为随机数的种子来生成 id,但
是 id 设置的比较短,一个存储的操作使用这个 id,在一些情况下,发生了冲突,当时做功
能测试这种小概率事件耗费了测试人员大量时间也没有稳定重现,还是在性能测试的阶段测
试了出来。
5.测试人员由于错误操作,出现了误报(这很常见)。比如,记得自己执行了 step3,其实没
有,或者没有正确执行 step 却觉得正确执行了。
怎样对付这样的 bug 呢?
我喜欢 James Bach 说的那句话:测试就像 CSI。CSI 是 CriminalScene Investigation 的缩写,
也是我非常喜欢的美国系列剧。
从我来看 CSI 的精髓在于:仔细观察,详细记录,科学分析,严密推理,有序求证,大胆
假设,持续不懈,团队协作和一点儿运气。找 bug 其实和 CSI 探员做犯罪现场调查没什么
太大区别。得知道,你工作的重要性一点儿不亚于 CSI 探员。
仔细观察
第一件事情就是要观察,观察你所做的一切操作和一切相关的系统反馈。在一开始,观察的
重要性要远远大于思考,通过观察你获得蛛丝马迹,这些蛛丝马迹是你进行思考和假设的关
键输入。例如,我在一次测试的过程中,发现做某种操作的时候会相当慢,极少数情况下还
报错过一两次,当询问了开发人员后得知这个操作的后台实现步骤是:先查看数据是否在缓
存中,如果不在,则从远端服务器请求数据。我抓住少数情况下会报错的这一现象,仔细观
察它的出错信息后猜测报错并不是因为网络连接不稳定引起的,而是由于远端服务接口实现
有问题引起的,后来重新设计了测试用例,果然找到了问题所在。如果不仔细观察出错信息,
就会听信开发人员认为这是网络不稳定引发的正常 issue 而错过这个 bug。
详细记录
详细记录你的操作步骤及返回结果非常有助于回朔问题,也有助于后续分析。准备一个 word
文档,和截图工具有时候非常必要。另外,在观察的时候,你不仅要注意被测物的最终返回,
还需要观察过程中的一些中间状态,往往这些中间状态提供的信息才是解开问题的关键。这
些中间状态一般会被记录在 log 文件中,因此知道你的被测物是如何记 log 的,log 被记录
在哪里非常重要。log 给了你另外一个看系统的角度。log 是有级别的,如果级别可以动态
调整,在找比较难找的 bug 时,可以将 log 记录的级别调至最低(DEBUG 级)让它们记录
更多内容。利用系统的错误转储文件(比如 linux 的 core dump 文件,windows 下也有相应
的记录转储文件的方式)分析也是个不错的办法(需要较高技术能力),但一般建议测试人
员把这些转储文件交给更专业的开发人员来分析。
除了 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
文件、监控记录、屏幕截图等。做一个负责人的测试人员,把烦恼真实的留给下家,这很重
要:)
其实上面的大段论述是站在测试人员角度上来看的。我也写很多代码,作为一个开发人员(哈
哈)我查错的方式一般是:
1.先能稳定的复现错误。(这一步最难)
2.设桩,打印出一些中间状态来分析,看到那一块儿错了。
3.摘除不相干的代码,慢慢迭代,定位错误。
4.如果发现调用第三方依赖跟你想的不一样,先读文档,然后再测试第三方依赖。有问题再
想办法。
5.良好的程序设计和单元测试覆盖度才是不二法门,会让你的调试变得简化的太多。。。用
过都说好:)
6.测试工作的确增强了我排错的能力。coding 的同学都尝试做几个月测试吧。会有相当大的
好处。
相关文章:

难以重现的 Bug如何处理
对很多测试人员(尤其是对新手来说)在工作过程中最不愿遇到的一件事情就是:在测试过 程中发现了一个问题,觉得是 bug,再试的时候又正常了。 碰到这样的事情,职业素养和测试人员长期养成的死磕的习性会让她…...

我与足球的故事 | 10年的热爱 | 伤病 | 悔恨 | 放弃 or 继续 | 小学生的碎碎念罢了
今天不分享技术博客,今天不知道为什么就是想写我和足球的故事(手术完两个礼拜,手还是很疼那个,就连打字都费劲),上面两张图是我最喜欢的两个球星,当然因为之前特别喜欢巴萨,也特别喜…...

js图片回显的方法
直接上代码: <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title></head><body>// HTML部分<input type"file" id"fileInput"><button onclick"show…...

Java中的maven的安装和配置
maven的作用 依赖管理 方便快捷的管理项目依赖的资源,避免版本冲突问题 统一项目管理 提供标准,统一的项目结构 项目构建 标准跨平台(Linux、windows、MacOS)的自动化项目构建方式 maven的安装和配置 在maven官网下载maven Ma…...

轴承制造企业“数智化”突破口
轴承是当代机械设备中一种重要零部件。它的主要功能是支撑机械旋转体,降低其运动过程中的摩擦系数,并保证其回转精度。轴承是工业核心基础零部件,对国民经济发展和国防建设起着重要的支撑作用。 轴承企业普遍采用以销定产的经营模式…...

UIButton案例之添加动画
需求 基于上一节代码进行精简,降低了冗余性。添加动画,使得坐标变化自然,同时使用了bounds属性和center属性,使得UIView变化以中心点为基准。 此外,使用两种方式添加动画:1.原始方式。 2.block方式。 代码…...

C#链接数据库、操作sql、选择串口
// 公共增删方法 using MySql.Data.MySqlClient; using System.Data; namespace ****** {public class MySQLHelper{private MySqlConnection conn null;private MySqlCommand comm null;private MySqlDataReader reader null;/// <summary>/// 构造方法里建议连…...

本地搭建各大直播平台录屏服务结合内网穿透工具实现远程管理录屏任务
文章目录 1. Bililive-go与套件下载1.1 获取ffmpeg1.2 获取Bililive-go1.3 配置套件 2. 本地运行测试3. 录屏设置演示4. 内网穿透工具下载安装5. 配置Bililive-go公网地址6. 配置固定公网地址 本文主要介绍如何在Windows系统电脑本地部署直播录屏利器Bililive-go,并…...

macos使用yarn创建vite时出现Usage Error: The nearest package directory问题
步骤是macos上使用了yarn create vite在window上是直接可以使用了yarn但是在macos上就出现报错 我们仔细看,它说的If /Users/chentianyu isnt intended to be a project, remove any yarn.lock and/or package.json file there.说是要我们清除yarn.lock和package.js…...

【JAVA入门】Day04 - 方法
【JAVA入门】Day04 - 方法 文章目录 【JAVA入门】Day04 - 方法一、方法的格式1.1 无参无返回值的方法定义和调用1.2 带参数的方法定义和调用1.3 形参和实参1.4 带返回值的方法定义和调用1.5 方法的注意事项 二、方法的重载三、方法的使用四、方法的内存原理4.1 方法调用的基本内…...

前端报错 SyntaxError: Unexpected number in JSON at position xxxx at JSON.parse
问题描述 控制台提示 SyntaxError: Unexpected number in JSON at position xxxx at JSON.parse 问题原因 原因:JSON 数据格式错误,是否符合 JSON 格式。 解决方法 应为json格式数据 什么是json格式数据 JSON(JavaScript Object …...

Mybatis进阶详细用法
目录 条件构造器 案例 自定义SQL 案例 Service接口 案例 综合案例 条件构造器 案例 Testvoid testQueryMapper() {// 创建 QueryWrapper 实例QueryWrapper<User> queryWrapper new QueryWrapper<>();queryWrapper.select("id," "username,&…...

Android 系统省电软件分析
1、硬件耗电 主要有: 1、屏幕 2、CPU 3、WLAN 4、感应器 5、GPS(目前我们没有) 电量其实是目前手持设备最宝贵的资源之一,大多数设备都需要不断的充电来维持继续使用。不幸的是,对于开发者来说,电量优化是他们最后才会考虑的的事情…...

了解什么是Docker
了解什么是Docker Docker 是一个开源的应用容器引擎,它允许开发者打包应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口(类…...

ChatGPT开源的whisper音频生成字幕
1、前言 好了,那接下来看一下whisper开源库的介绍 有五种模型大小,其中四种仅支持英语,提供速度和准确性的权衡。上面便是可用模型的名称、大致的内存需求和相对速度。如果是英文版的语音,直接想转换为英文。 本来我是想直接在我的…...

融知财经:期货和现货的区别是什么?哪个风险大?
期货和现货在交易对象等方面存在明显的区别。期货交易是一种衍生金融工具,主要用于价格发现、风险管理和投机,而现货交易则是商品和服务的实际买卖。在选择进行期货交易还是现货交易时,投资者需要根据自己的需求和市场情况来决定。 期货和现货…...

Android Studio开发之路(十)app中使用aar以及报错记录
书接上文:Android Studio开发之路(九)创建android library以及生成aar文件 五、app中使用aar文件的方法 先复制一下上面生成的aar文件。然后在你要添加到的app左上角选择“project”模式,然后找到libs文件夹,点击右键…...

sql-行转列3(转置)
行转列的常规做法是,group bysum(if())【或count(if())】 例题: 腾讯QQ 假设tableA如表5, tableB如表6, 表5 qq号(字段名:qq)游戏(字段名:game)10000a10000b10000c20000c20000d…...

MATLAB | 最新版MATLAB绘图速查表来啦!!
之前看大佬Pjer做的MATLAB速查表 http://home.ustc.edu.cn/~pjer1316/matlabplot/ 感觉非常的实用,最近几次MATLAB更新围绕画图方面也有很多新东西,于是就有了自己做一张最新版的速查表的想法,这张表长这样: 这张表的配色基本上…...

web安全之登录框渗透骚姿势,新思路
不管漏洞挖掘还是挖SRC,登录框都是重点关注对象,什么漏洞都有可能出现, 本篇文章做个总结,后面发现新思路后会继续更新 万能密码 or 弱口令 SQL注入 水平越权 垂直越权 逻辑漏洞 短信轰炸 邮箱轰炸 信息泄露 验证码DOS XSS万能密…...

无人机+自组网:空地点对点无人机通信解决方案
随着智能化技术的迅速发展, 无人化设备在战场上发挥的作用日益突显。在近期发生的多次局部战争中, 无人设备代替人类承担了多项危险且复杂的攻击任务, 达到 “兵不血刃” 的效果. 2020 年 1 月 3 日, 美军利用无人机执行了刺杀伊朗 “圣城旅” 指挥官苏莱曼尼行动. 纳戈尔诺 - …...

android TV app适配遥控器思路,recycleview选中放大
背景: 1、当遥控器遥控盒子,app内是有一套机制,响应遥控器的操作; 2、要实现遥控器选中的效果,必须要设置setOnFocusChangeListener方法,另外一个就是设置view的setOnClickListener方法;设置完之后&#…...

python篇-cmd 执行pip命令失败,但执行pyhon命令正常
当你在CMD中可以正常执行python命令,但执行pip命令失败时,这通常意味着pip没有被正确地添加到系统的环境变量中。这里有一些步骤来解决这个问题: 检查环境变量: 打开系统的环境变量设置(右击“此电脑”>“属性”>…...

Redis系列-3 Redis缓存问题
1.缓存的作用 数据库(如Mysql)的持久化特点带来了较低的性能,高并发的场景下,连接池很快被耗尽而出现宕机或DOS,无法继续对外提供服务。相对于数据库的硬盘IO,缓存中间件基于内存进行读写,从而具备较大的吞吐量和高并…...

【数据结构】堆(Heap)
文章目录 一、堆的概念及结构二、堆的实现1.向上调整算法2.向下调整算法3.堆的创建4.堆的插入5.堆的删除6.堆的其他操作 三、堆的应用1.堆排序2.Top-K问题 一、堆的概念及结构 堆(Heap)是一种特殊的非线性结构。堆中的元素是按完全二叉树的顺序存储方式存储在数组 中。满足任意…...

vue cli 自定义项目架子,vue自定义项目架子,超详细
脚手架Vue CLI基本介绍: Vue CLI 是Vue官方提供的一个全局命令工具 可以帮助我们快速创建一个开发Vue项目的标准化基础架子【集成了webpack配置】 脚手架优点: 开箱即用,零配置内置babel等工具标准化的webpack配置 脚手架 VueCLI相关命令…...

flink cdc,读取datetime类型
:flink cdc,读取datetime类型,全都变成了时间戳 Flink CDC读取MySQL的datetime类型时会转换为时间戳的问题,可以通过在Flink CDC任务中添加相应的转换器来解决。具体来说,可以在MySQL数据源的debezium.source.converter配置项中指…...

Kotlin 编译器和工具链:深入解析与实践案例
Kotlin 编译器和工具链是构建 Kotlin 项目的核心组件,它们负责将 Kotlin 代码转换为可在 JVM 或 JavaScript 环境中运行的代码。本文将详细介绍 Kotlin 编译器和工具链的工作原理、使用方法,以及在实际开发中的应用案例。 1. 引言 Kotlin 作为一种现代…...

kettle
文章目录 读取共享数据库连接报错 读取共享数据库连接报错 读取共享数据库连接报错 解决方法:修改共享文件中的中文字符,文件位置一般是默认的:C:\Users\Administrator.kettle。将shared.xml文件中的中文字符改成英文后问题就解决了。...

Maven 自动化构建
优质博文:IT-BLOG-CN 一、Maven:是一款服务于 Java平台的自动化构建工具 【1】Maven可以将一个项目按模块划分成不同的工程,利于分工协作; 【2】Maven可以将 jar包保存在自己的中央“仓库”中进行统一管理,有需要使用的工程引用这…...