那張被關掉的 bug ticket,讓我搞懂什麼叫做真正的 bug report

#測試策略 #Bug Report

<h1 那張被關掉的 bug ticket,讓我搞懂什麼叫做真正的 bug report</h1 <hr <h2 目錄</h2 <ol <li <p <a target=" blank" rel="noopener noreferrer nofollow" href=" %E9%82%A3%E5%BC%B5%E8%A2%AB%E6%A8%99%E6%88%90 cannot reproduce %E7%9A%84 ticket" 那張被標成 Cannot Reproduce 的 ticket</a </p </li <li <p <a target=" blank" rel="noopener noreferrer nofollow" href=" %E6%88%91%E7%95%B6%E6%99%82%E7%9A%84%E7%90%86%E8%A7%A3" 我當時的理解:把看到的事情寫下來就好</a </p </li <li <p <a target=" blank" rel="noopener noreferrer nofollow" href=" %E5%95%8F%E9%A1%8C%E5%9C%A8%E5%93%AA%E8%A3%A1" 問題其實不在功能,在於我的描述方式</a </p </li <li <p <a target=" blank" rel="noopener noreferrer nofollow" href=" %E6%88%91%E7%8F%BE%E5%9C%A8%E6%80%8E%E9%BA%BC%E5%AF%AB" 我現在怎麼寫</a </p </li <li <p <a target=" blank" rel="noopener noreferrer nofollow" href=" %E7%B5%90%E5%B0%BE" 結尾</a </p </li </ol <hr <h2 那張被標成 Cannot Reproduce 的 ticket</h2 <p 那是我做 QA 第三個月,正在測 我們的 App 的計時種樹功能。</p <p 我發現一個問題:完成一次 25 分鐘的專注計時後,結束畫面顯示「種植成功」,但回到森林主頁,那棵樹沒有出現。硬幣也沒有增加。我覺得這是個很明顯的 bug,馬上開了一張 ticket,寫了這樣:</p <blockquote <p <strong 標題:</strong 計時結束後樹木未種植 <strong 描述:</strong 完成計時後畫面顯示種植成功,但森林主頁沒有新樹,硬幣也沒有增加。</p </blockquote <p 送出去,自信滿滿等開發處理。</p <p 兩天後 ticket 被標成 <code Cannot Reproduce</code ,後面還有一句備註:「請補充測試步驟與帳號狀態。」</p <p 我當時有點生氣,心想這麼明顯的 bug 你找不到?後來我去找了開發,跟他坐在一起重現,才知道這個 bug 只有在帳號「第一次種樹」的狀態下才會發生——已經有種植紀錄的帳號不會觸發。而且需要是透過 Google 或 Apple 登入的連結帳號,本地帳號沒有這個問題。</p <p 開發說:「你的描述裡這些條件都沒有,我用自己的帳號試了三次當然找不到。」</p <p 他說得對。</p <hr <h2 我當時的理解</h2 <p 我那時候的理解是:bug report 就是把你看到的異常寫下來,讓開發知道有問題。</p <p 所以我的 ticket 通常長這樣:</p <ul <li <p 標題:哪裡壞了</p </li <li <p 描述:看到了什麼</p </li </ul <p 我以為這樣就夠了。畢竟我知道怎麼重現,如果開發有問題可以來找我。</p <p 這個想法讓我之後花了很多時間在 Slack 上解釋 ticket,幫開發補步驟,甚至親自坐到他旁邊示範。效率極差,而且 sprint 到後半段人人都很忙,這種來來回回很容易讓 bug 被往後排或直接被忽略。</p <p 更糟糕的是,有幾次 bug 被「修了」,但修的不是我回報的那個問題,而是開發自己猜到的另一個可能性。後來 regression 的時候才發現原始問題還在。</p <hr <h2 問題在哪裡</h2 <p 後來有個資深 QA 看了我的幾張 ticket,直接跟我說:「你的 report 是寫給自己看的,不是寫給開發看的。」</p <p 這句話讓我想了很久。</p <p 一份 bug report 真正的目的不是「讓對方知道有 bug」,而是「讓對方能夠在沒有你的情況下重現這個 bug,然後修掉它」。</p <p 這兩件事差很多。</p <p 前者只需要描述結果,後者需要提供足夠的上下文讓另一個人可以獨立重現。而且那個「另一個人」可能是一週後才看到你 ticket 的開發,中間沒有你可以問。</p <p 我發現問題出在三個地方:</p <p <strong 前置條件沒寫清楚。</strong 帳號狀態、登入方式、已有的資料都是條件。很多 bug 只在特定狀態下觸發,你不說開發不會知道。我們的 App 的很多 bug 都跟帳號是否有種植紀錄、訂閱狀態、用哪種方式登入高度相關。</p <p <strong 步驟寫得太模糊。</strong 「完成計時後查看森林」這樣的描述,開發不知道你計時了幾分鐘、選了哪種樹、有沒有在計時中途切換 app。每一步都要精確到動作層級。</p <p <strong 環境資訊缺失。</strong 同一個 bug 在 iOS 和 Android 上行為可能不同,在不同帳號狀態下行為也不同。App 版本、裝置、OS 版本都可能影響重現結果,這些不是多餘的資訊,是重現的必要條件。</p <hr <h2 我現在怎麼寫</h2 <p 現在我的 bug report 結構固定是這樣:</p <p <strong 1. 標題:行為 + 條件</strong </p <p 不是「樹木未種植」,是「連結帳號首次種樹後,森林主頁無新樹且硬幣未增加(v6.2.1+,iOS)」。</p <p 標題要讓人一眼知道在哪裡、什麼情況、什麼問題。開發在看 ticket list 的時候,能從標題就大概判斷影響範圍,這很重要。</p <p <strong 2. 前置條件</strong </p <pre <code 前置條件: 使用帳號:全新 Google 連結帳號(從未種過樹) 帳號狀態:無種植紀錄、無訂閱 計時設定:25 分鐘,選擇「橡樹」(免費樹種) App 版本:6.2.1 裝置:iPhone 15 Pro,iOS 17.3 環境:Staging </code </pre <p 這段不用寫得漂亮,清單就好,但要完整。</p <p <strong 3. 重現步驟</strong </p <pre <code 重現步驟: 1. 以 Google 帳號登入(確認帳號無種植紀錄) 2. 點擊首頁「開始種樹」 3. 選擇橡樹,設定計時 25 分鐘 4. 點擊「開始」,等待計時結束(或手動快轉) 5. 計時結束,點擊「種植」 6. 觀察結束畫面顯示「種植成功」 7. 返回森林主頁,查看是否有新樹 8. 查看帳號硬幣數量是否增加 </code </pre <p 每一步是一個動作,數字排列,不要合併步驟。</p <p <strong 4. 實際結果 vs. 預期結果</strong </p <pre <code 實際結果: 結束畫面顯示「種植成功」,但返回森林後無新樹, 硬幣數量維持原本的 0 枚,未獲得本次計時應得的 25 枚。 預期結果: 森林主頁出現新種植的橡樹, 帳號硬幣從 0 枚增加至 25 枚。 </code </pre <p 這兩欄要分開寫,不要混在一起。很多人習慣只寫「實際結果」,但開發需要知道你預期什麼,才能判斷這是 bug 還是設計如此。</p <p <strong 5. 附件</strong </p <p 截圖或影片。不是裝飾,是證據。</p <p 截圖要包含顯示問題的那一刻,如果流程複雜,錄一段影片比截十張圖有用。檔案命名要有意義,<code screenshot 2024.png</code 沒有 <code forest empty after plant success.png</code 有用。</p <p <strong 6. 嚴重程度(Severity)</strong </p <p 這個很多人會跳過或者亂填,但它影響 bug 被處理的順序。</p <p 我的判斷基準是:</p <ul <li <p <strong Critical</strong :主流程完全壞掉,無法進行(計時功能無法啟動、App 閃退)</p </li <li <p <strong High</strong :主流程可完成,但結果錯誤(種樹成功畫面出現,但樹沒有種進去)</p </li <li <p <strong Medium</strong :非主流程異常,或有 workaround(重新整理後樹才出現)</p </li <li <p <strong Low</strong :UI 問題、文案錯誤、不影響功能</p </li </ul <p 上面那個首次種樹 bug 是 High,因為它讓新用戶在最重要的第一次體驗就看到「成功」但實際沒有成功,嚴重影響信任感,而且新帳號比例不低。</p <p 一份完整的 ticket 大概長這樣:</p <pre <code class="language markdown" [High] 連結帳號首次種樹後,森林無新樹且硬幣未增加(v6.2.1+,iOS) 前置條件 帳號:全新 Google 連結帳號(無種植紀錄、無訂閱) 計時:橡樹,25 分鐘 App:v6.2.1,iPhone 15 Pro,iOS 17.3 環境:Staging 重現步驟 1. Google 登入(確認帳號無種植紀錄) 2. 開始種樹,選擇橡樹,計時 25 分鐘 3. 計時結束,點擊「種植」 4. 觀察結束畫面,返回森林主頁 實際結果 結束畫面顯示「種植成功」,返回後無新樹,硬幣未增加(仍為 0) 預期結果 森林出現橡樹,硬幣增加 25 枚 備註 本地帳號(非連結帳號)無此問題 已有種植紀錄的連結帳號無此問題 附影片:forest first plant bug.mp4 </code </pre <hr <p 有幾件事我現在很確定:</p <p <strong Bug report 要寫給沒看過這個 bug 的人。</strong 你在意的是「能讓對方重現」,不是「記錄我測到了什麼」。這個心態的差別,決定你會不會主動補前置條件和環境資訊。</p <p <strong 步驟寫完要自己試跑一次。</strong 很多時候寫完才發現少了一步,或者順序不對。你在寫的時候腦中有完整的流程,但讀的人沒有。</p <p <strong 不要只附截圖,截圖要有標記。</strong 圈出問題在哪裡,加箭頭,用紅框。開發看到一張全畫面截圖,還要自己找問題在哪,這是在浪費對方的時間。</p <p <strong 嚴重程度不要全部填 Critical。</strong 我見過有人每張 ticket 都填 Critical,後來開發完全忽略這個欄位。這個欄位是溝通工具,用壞了就沒有意義了。</p <hr <h2 結尾</h2 <p 寫出一份好的 bug report,不是為了讓自己看起來更專業,是為了讓問題被正確、快速地處理。</p <p 那張被標成 <code Cannot Reproduce</code 的 ticket,責任不在開發找不到,在我沒有給他足夠的資訊。這個認知讓我後來每次寫 ticket 之前都會多問自己一句:「如果是我第一次看這張 ticket,我能重現這個問題嗎?」</p <p 這個問題問了幾百次之後,現在大部分的 ticket 我不需要在 Slack 上補充說明。省下來的時間,兩邊都受益。</p <p 我還是會偶爾漏掉某個環境條件,或者步驟寫得不夠精確。這不是一次學完的事,是每次開 ticket 都需要有意識地去做的事。</p <hr <p <em 如果你的 ticket 常常被要求補充資訊,或者被標成 Cannot Reproduce,值得回頭看看這些地方。</em </p