遇到的两个bug

3 阅读15分钟

两个真实软件 Bug 分析:从现象到排查思路

这篇文章记录两个我在实际使用和测试过程中遇到的真实 Bug。

我想把它们整理出来,不只是为了“记住一个问题”,而是训练自己从下面几个角度看 Bug:

  • 现象是什么
  • 如何稳定复现
  • 影响范围在哪里
  • 更可能是哪一层出了问题
  • 如果我是测试,下一步应该怎么追

这两个 Bug 分别是:

  1. 腾讯元宝网页端,复制上传 1 张图片后,聊天框里出现十几张相同图片
  2. 测试实习期间,手机客户端切换账号登录时,App 会先退出回到桌面,再自动重新打开

这两个问题一个偏 Web 端交互 / 前端状态管理,一个偏移动端登录态切换 / App 生命周期管理,刚好很适合放在一起分析。


一、Bug 分析方法:不要只停留在“看到了异常”

很多人记录 Bug 时,只会写:

  • 现象:出问题了
  • 结果:不符合预期

这样当然可以提单,但如果你想提升自己的分析能力,还不够。

更有价值的方式是把 Bug 拆成 5 个问题:

1. 触发路径是什么

也就是:

  • 用户做了什么操作
  • 哪一步之后出现异常

2. 异常表现是什么

也就是:

  • 页面错了
  • 数据重复了
  • 状态丢了
  • 应用闪退了

3. 预期行为应该是什么

这一点非常重要,因为“Bug”本质上是实际结果和预期结果不一致。

4. 更可能是哪个模块出的问题

比如:

  • 前端事件重复触发
  • 接口重复请求
  • 后端去重失效
  • 客户端生命周期处理错误

5. 如果继续排查,要看什么证据

例如:

  • 前端控制台日志
  • Network 请求
  • App 日志
  • 埋点
  • 崩溃日志
  • 服务端请求链路

下面我就按这个思路来拆这两个真实 Bug。


二、Bug 1:腾讯元宝网页端复制上传 1 张图片,却出现十几张相同图片

1. Bug 现象

我在腾讯元宝网页端使用“复制图片并粘贴上传”的方式发送图片。

按预期,我只复制了 1 张图片,聊天框里应该只出现 1 张待发送图片,或者 1 条图片消息。

但实际现象是:

  • 我只进行了一次复制 / 粘贴操作
  • 聊天框里却出现了十几张相同的图片

也就是说,系统把一次用户操作放大成了多次重复结果。

2. 预期行为

预期应该是:

  • 一次粘贴操作,对应一次图片插入
  • 聊天框中最多出现 1 张对应图片
  • 即使内部存在异步处理,也不应该出现明显重复

3. 可能的复现路径

可以先把复现步骤写成标准测试步骤:

  1. 打开腾讯元宝网页端聊天页面
  2. 复制一张图片
  3. 聚焦到聊天输入框
  4. 执行粘贴操作,例如 Ctrl + V
  5. 观察聊天框中的待发送图片或消息内容

预期结果:

  • 仅出现 1 张图片

实际结果:

  • 出现十几张相同图片

4. 这个 Bug 的第一直觉:大概率不是“图片本身有问题”

因为问题不是:

  • 图片格式错
  • 图片上传失败
  • 图片显示损坏

而是:

  • 同一张图片被重复插入很多次

这说明问题更像是:

  • 同一个事件被处理了多次
  • 同一个数据被渲染了多次
  • 同一个上传任务被创建了多次

所以从经验上看,这类问题的优先怀疑方向通常是:

  • 前端事件监听重复绑定
  • 粘贴事件和上传逻辑没有做幂等保护
  • 剪贴板中多个数据项被重复解析
  • 前端状态更新重复触发渲染

5. 更细一点看,可能是哪几类原因

原因方向 1:paste 事件被重复监听

网页端常见做法是监听输入框的 paste 事件,然后从剪贴板里读取图片数据。

如果代码里发生了下面这种问题:

  • 页面重渲染后重复绑定事件
  • 每次进入会话都追加一次监听
  • 组件卸载时没清理监听器

那一次粘贴就可能触发多次处理逻辑。

这种情况下的典型现象是:

  • 一次用户操作
  • 多次进入同一段处理函数
  • 最终生成多条重复数据

原因方向 2:剪贴板数据被循环处理,但没有正确过滤

浏览器剪贴板里不一定只有“单一图片对象”。

有时一次复制动作里可能包含:

  • 图片二进制数据
  • HTML 片段
  • 文本描述
  • 多种 MIME 类型

如果前端在遍历 clipboardData.items 时:

  • 没有筛选真正的图片项
  • 或者对同一数据重复转换

就可能把“同一张图片”当成多份资源处理。

原因方向 3:前端上传逻辑重复创建任务

也有一种可能不是展示层的问题,而是上传队列的问题。

比如:

  • 粘贴后先本地预览一次
  • 再自动触发上传
  • 上传完成后又补插入一次
  • 某个重试逻辑把同一个任务重复加入队列

这时最终表现也可能是:

  • 聊天框中出现多张相同图片
  • 或者消息区里出现多条相同图片消息

原因方向 4:状态管理重复追加

假设前端使用状态管理维护待发送图片列表:

  • 正常应是 list = [imageA]

但如果代码在多个地方都执行了 append(imageA),就会出现:

  • list = [imageA, imageA, imageA, ...]

这类问题常见于:

  • 监听器多次触发
  • 异步回调重复执行
  • React / Vue 状态更新逻辑写得不严谨

6. 如果我是测试,下一步怎么排

第一步:先判断是“展示重复”还是“请求重复”

这个很关键。

因为:

  • 如果只是前端展示重复,Network 里可能只发 1 次上传请求
  • 如果请求也重复,说明上传任务本身被创建了多次

所以第一步最值得看的就是浏览器开发者工具里的:

  • Network
  • Console

第二步:看一次粘贴是否触发多次请求

重点观察:

  • 是否一次 Ctrl + V 后产生多条上传请求
  • 请求参数是否相同
  • 时间间隔是否极短

如果是多条相同请求,问题更偏:

  • 事件重复触发
  • 上传逻辑缺少幂等

第三步:如果请求只有一次,重点怀疑前端渲染或状态

这时应该关注:

  • 前端是否对同一结果多次 setState
  • 是否本地预览和服务端回填都在追加
  • 是否列表 key 不正确导致渲染异常

第四步:补做对比实验

为了进一步缩小范围,我会继续做这些对比:

  • 复制上传图片 vs 手动选择图片上传
  • 粘贴本地截图 vs 粘贴网页图片
  • 不同浏览器下是否都能复现
  • 无痕模式 / 清缓存后是否仍复现

这些对比可以帮助判断问题更偏:

  • 浏览器兼容性
  • 剪贴板数据格式
  • 页面状态污染

7. 这个 Bug 给我的测试启发

这个问题很典型地说明了一件事:

输入类功能,不只是测“能不能成功”,还要测“是否只执行一次”。

很多测试容易漏掉“重复触发”这类问题,尤其在下面这些场景:

  • 粘贴
  • 双击
  • 连点
  • 拖拽上传
  • 回车发送
  • 自动重试

这类场景都很容易出现:

  • 重复提交
  • 重复渲染
  • 重复请求

所以以后碰到上传、发送、提交、支付、下单这类动作时,我会特别注意:

  • 幂等性
  • 事件防抖 / 节流
  • 前端重复绑定
  • 队列去重

三、Bug 2:手机客户端切换账号登录时,先退出回到桌面,再自动重新打开

1. Bug 现象

在测试实习期间,我遇到过这样一个手机客户端问题:

  • 用户切换账号登录
  • App 会先退出
  • 返回到手机桌面
  • 随后又自动重新打开 App

从用户视角看,这个体验非常怪:

  • 像闪退
  • 但又不是彻底闪退
  • 因为它会自动重新拉起

2. 预期行为

正常的账号切换登录流程应该是:

  • 当前账号退出
  • 清理旧账号登录态
  • 切换到登录页或重新进入首页
  • 整个过程尽量平滑,不应突然回桌面

也就是说,哪怕内部确实做了很多状态重置,用户也不应该感知到:

  • App 被“杀掉又重启”

3. 这类问题为什么很值得分析

因为它不是一个简单的页面展示问题,而是明显涉及:

  • 登录态切换
  • 客户端生命周期
  • 页面路由重建
  • 进程 / Activity / App 重启机制

这类 Bug 往往比普通表单错误更有分析价值,因为它牵涉系统层和业务层交叉。

4. 第一判断:它不一定真的是“闪退”

用户看到“回到桌面再重新打开”,第一反应往往是:

  • App 崩了

但从测试分析角度,不能马上下这个结论。

因为还存在另一种可能:

  • 业务代码主动结束当前页面栈或进程
  • 然后通过某种方式重新拉起 App

所以这个问题至少有两种大方向:

方向 1:真的崩溃了,然后系统或框架做了自动重启

例如:

  • 账号切换后某个页面拿到空对象
  • 引发崩溃
  • 框架内置崩溃恢复机制把 App 再次拉起

方向 2:程序主动做了“重启应用”式处理

例如:

  • 切换账号后为了清空全局状态
  • 直接 finishAffinity() 或类似操作结束当前页面
  • 再通过启动页重新拉起 App

这种实现方式如果没处理好,就会让用户明显看到:

  • 先退桌面
  • 再重新打开

5. 更可能的原因方向

原因方向 1:账号切换后需要重建全局状态,但实现方式过于粗暴

切换账号时,很多信息都要重置:

  • token
  • 用户信息
  • 首页缓存
  • WebView 登录态
  • IM / 推送绑定关系
  • 本地数据库中的用户相关数据

如果研发为了省事,采用“重启 App”方式强制清理状态,这在实现上确实简单,但用户体验很差。

这类问题的典型表现就是:

  • 切换账号时应用明显退出
  • 然后重新拉起冷启动流程

原因方向 2:路由栈清理异常

另一个常见原因是页面栈处理不对。

例如:

  • 退出登录时清掉所有 Activity
  • 但登录成功后又自动跳启动页
  • 中间没有平滑过渡

这种情况下,从外部看也很像“先退出回桌面,再重新打开”。

原因方向 3:登录成功后触发了进程级重建

有些 App 在账号切换后会重建:

  • 多语言
  • 主题
  • 用户态配置
  • 首页容器

如果重建发生在进程级或应用级,就可能造成明显闪断。

原因方向 4:某个页面在切换账号时访问了失效数据,导致异常退出

比如:

  • 当前页面还持有旧用户数据
  • 退出后 token 已清空
  • 但页面异步回调还在执行
  • 最后访问空对象或非法状态

这时就可能出现:

  • 先异常退出
  • 再因启动保护逻辑自动拉起

6. 如果我是测试,该怎么进一步定位

第一步:先判断是“主动重启”还是“崩溃重启”

这是最重要的一步。

因为这决定了排查方向完全不同。

如果是主动重启,日志里通常会看到:

  • 明确的退出登录逻辑
  • 清理页面栈逻辑
  • 重新拉起启动页逻辑

如果是崩溃重启,日志里更可能出现:

  • 崩溃栈
  • uncaught exception
  • ANR / fatal error

第二步:看客户端日志和生命周期日志

重点关注:

  • 退出登录按钮点击后发生了哪些调用
  • Activity / App 生命周期如何变化
  • 是否调用了清栈 / 重启相关 API

例如 Android 场景下会特别关注:

  • onPause
  • onStop
  • onDestroy
  • 新启动页的 onCreate

如果这些日志连起来看,就能判断:

  • 是不是代码主动做了“销毁旧栈再拉起新栈”

第三步:看切换账号过程中是否有异步任务没收干净

切换账号时很容易出问题的地方包括:

  • 网络请求还没结束
  • WebSocket / 长连接还没断干净
  • 推送绑定关系还没切换完
  • 本地缓存还没清完
  • 首页异步刷新还在执行

这些任务如果和新账号切换过程并发交错,就很容易造成状态异常。

第四步:做场景对比

为了缩小范围,我会继续补这些测试:

  • 冷启动后立即切换账号是否复现
  • 已登录使用一段时间后切换账号是否复现
  • 弱网下切换账号是否更容易复现
  • 不同机型、不同系统版本是否都复现
  • 从 A 账号切 B 账号复现,从 B 切 A 是否也复现

这样可以判断问题更偏:

  • 机型兼容
  • 时序问题
  • 异步任务清理不彻底

7. 这个 Bug 暴露的本质问题

这个问题很有代表性,因为它暴露出“登录态切换”不是一个简单页面跳转问题。

它背后通常关联的是整套用户态系统:

  • 本地缓存
  • 登录 token
  • 页面栈
  • 长连接
  • 推送
  • 用户数据隔离

所以测试账号切换时,不能只测:

  • 能不能登录成功

还要测:

  • 登录后页面是否正确
  • 退出后状态是否清空
  • 切换账号后是否串数据
  • 是否出现闪退、重启、白屏、卡死

8. 这个 Bug 给我的测试启发

这个问题让我特别意识到:

登录、退出、切换账号这类场景,本质上是“高风险状态切换场景”。

高风险的原因在于:

  • 涉及全局状态重置
  • 涉及本地和服务端双向状态同步
  • 涉及页面栈和生命周期变化
  • 涉及异步任务收尾

所以以后测这类功能,我会特别关注:

  • 是否有页面闪断
  • 是否回到桌面
  • 是否白屏
  • 是否自动重启
  • 是否串账号数据
  • 是否存在旧账号残留信息

四、把这两个 Bug 放在一起看,我学到了什么

虽然这两个 Bug 一个发生在网页端,一个发生在移动端,但它们有一个共同点:

都不是“功能完全不能用”,而是“状态管理和事件处理出了问题”。

第一个 Bug 的核心更像:

  • 一次输入事件被多次消费
  • 前端状态或上传任务没有做好去重

第二个 Bug 的核心更像:

  • 用户状态切换时,全局生命周期没有处理平滑
  • 页面栈、登录态、异步任务之间存在冲突

这两类问题都说明:

测试不能只停留在“点一下能不能成功”。

更要关注:

  • 事件是否重复触发
  • 状态是否重复写入
  • 切换过程是否平滑
  • 全局状态是否真正收敛

五、如果把这两个 Bug 讲给面试官,怎么说更好

如果面试官问你:

  • 你遇到过什么印象深刻的 Bug
  • 你怎么分析一个 Bug
  • 你怎么从 Bug 里提升自己

你完全可以把这两个例子讲出来。

推荐表达方式不是只说“我遇到过一个重复上传 Bug”,而是按下面结构:

  1. 先说现象
  2. 再说预期
  3. 再说你怎么判断问题可能在哪一层
  4. 再说如果继续排查你会看什么
  5. 最后说这个 Bug 给你的测试启发

比如可以这样总结:

我遇到过一个网页端图片粘贴上传 Bug,一次粘贴只传 1 张图,但聊天框出现十几张相同图片。这个问题让我第一时间怀疑不是图片本身,而是粘贴事件被重复消费、上传队列去重失败或者前端状态重复追加。后来我也总结出一个经验:凡是上传、发送、支付、下单这种动作,都要特别关注幂等性和重复触发问题。

再比如移动端那个:

我在实习中还遇到过切换账号登录时 App 先退到桌面再自动重新打开的问题。这个 Bug 让我意识到账号切换不是一个简单登录功能,而是一个高风险全局状态切换场景。后续我在测登录态相关功能时,会特别关注页面栈清理、缓存清理、异步任务收尾和旧账号数据残留。


六、最后的总结

真正有价值的 Bug 复盘,不只是记住“哪里错了”,而是逐渐训练出下面这些能力:

  • 看到现象后先分类
  • 知道优先怀疑哪一层
  • 知道下一步该抓什么证据
  • 能把 Bug 转化成后续测试策略

对测试工程师来说,这种能力比单纯记很多八股更重要。

因为你以后不管是在面试里,还是在项目里,真正拉开差距的往往不是“知道多少名词”,而是:

你能不能把一个异常现象,快速拆成清晰的问题,并形成靠谱的分析路径。