<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Flaky Test on Tarragon</title><link>https://tarrragon.github.io/blog/tags/flaky-test/</link><description>Recent content in Flaky Test on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Thu, 21 May 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/flaky-test/index.xml" rel="self" type="application/rss+xml"/><item><title>Flaky test 治理</title><link>https://tarrragon.github.io/blog/ci/flaky-test-governance/</link><pubDate>Thu, 21 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/ci/flaky-test-governance/</guid><description>&lt;p>Flaky test 治理的核心責任是保護 CI gate 的信任度。&lt;a href="https://tarrragon.github.io/blog/ci/knowledge-cards/flaky-test/" data-link-title="Flaky Test" data-link-desc="說明非決定性測試如何降低 CI gate 信任度與治理方式">Flaky test&lt;/a> 會讓團隊開始用重跑取代判讀，最後讓紅燈失去阻擋意義。&lt;/p>
&lt;h2 id="概念定位">概念定位&lt;/h2>
&lt;p>Flaky test 是非決定性的 gate 訊號。它的危害不只在延遲 merge，而是在心理上訓練團隊忽略紅燈；當真回歸出現時，大家也可能先按 rerun。治理目標是把 flaky 分類、隔離、修復，並保持 required checks 的語意可信。&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>階段&lt;/th>
 &lt;th>責任&lt;/th>
 &lt;th>判讀訊號&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>Detect&lt;/td>
 &lt;td>找出非決定性失敗&lt;/td>
 &lt;td>同 commit 重跑結果不一致&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Classify&lt;/td>
 &lt;td>區分測試、環境、資料與產品問題&lt;/td>
 &lt;td>failure pattern、log、trace&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Contain&lt;/td>
 &lt;td>降低對主線 gate 的污染&lt;/td>
 &lt;td>quarantine、owner、expiry&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Fix&lt;/td>
 &lt;td>修掉根因&lt;/td>
 &lt;td>timing、isolation、mock、resource&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Re-admit&lt;/td>
 &lt;td>恢復 gate 信任&lt;/td>
 &lt;td>連續穩定、觀測窗口、owner sign-off&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>Detect 階段負責證明 flakiness。單次失敗不應直接貼 flaky 標籤；要看同一 commit、同一測試、相近環境下是否出現 pass / fail 不一致，並保存 log、trace、screenshot 或 seed。&lt;/p>
&lt;p>Classify 階段負責找根因方向。常見來源包含時間競態、測試順序依賴、共享狀態、外部服務、隨機資料、資源不足、瀏覽器 layout timing、網路模擬與 CI runner 差異；不同來源需要不同修法。&lt;/p>
&lt;p>Contain 階段負責保護主線。高價值但暫時 flaky 的測試可以進 quarantine workflow，但必須有 owner、issue、到期日與 replacement gate；直接從 required checks 移除而不追蹤，等於降低品質基線。&lt;/p>
&lt;p>Fix 階段負責消除非決定性。常見修法是移除固定 sleep、改用可觀察條件等待、隔離資料、固定 random seed、避免測試共享全域狀態、mock 不穩定外部依賴或調整資源限制。&lt;/p>
&lt;p>Re-admit 階段負責把測試放回 gate。測試修完後應在多次 workflow、不同 runner 或足夠時間窗口中穩定通過，再恢復 required checks；否則 gate 會反覆被污染。&lt;/p>
&lt;h2 id="分類矩陣">分類矩陣&lt;/h2>
&lt;p>分類矩陣的責任是讓 flaky issue 有明確修復路由。沒有分類時，團隊容易只留下「偶發失敗」這種不可執行標籤。&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>類型&lt;/th>
 &lt;th>常見訊號&lt;/th>
 &lt;th>修復方向&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>Timing&lt;/td>
 &lt;td>sleep 不足、元素尚未出現&lt;/td>
 &lt;td>等待可觀察條件、移除固定 sleep&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Shared state&lt;/td>
 &lt;td>單跑通過、整批失敗&lt;/td>
 &lt;td>隔離資料、清理全域狀態&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Order&lt;/td>
 &lt;td>測試順序改變後失敗&lt;/td>
 &lt;td>移除順序依賴、獨立 setup&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>External&lt;/td>
 &lt;td>第三方 API、網路或時間服務不穩&lt;/td>
 &lt;td>mock、contract fixture、retry boundary&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Resource&lt;/td>
 &lt;td>CI runner 負載高時失敗&lt;/td>
 &lt;td>降低 parallelism、設定 resource&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Product race&lt;/td>
 &lt;td>真實功能存在競態&lt;/td>
 &lt;td>回到產品修復，不只改測試&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>這張表的邊界是：flaky 可能來自測試，也可能來自產品 race condition。若測試揭露的是產品 race condition，它應該被當成真 bug 處理。&lt;/p>
&lt;h2 id="quarantine-契約">Quarantine 契約&lt;/h2>
&lt;p>Quarantine 的責任是暫時隔離污染，並維持 gate 的長期品質基線。隔離測試時，要把責任、期限與替代風險控制寫清楚。&lt;/p>
&lt;ol>
&lt;li>每個 quarantine test 必須有 issue 與 owner。&lt;/li>
&lt;li>每個 issue 必須標明分類、失敗證據與修復方向。&lt;/li>
&lt;li>Required checks 若移除測試，要補 replacement gate 或風險說明。&lt;/li>
&lt;li>Quarantine workflow 仍需定期跑，並回報趨勢。&lt;/li>
&lt;li>到期未修復時要重新評估：修、刪、改寫或降級測試責任。&lt;/li>
&lt;/ol>
&lt;p>這個契約讓 quarantine 成為治理工具。沒有期限與 owner 的 quarantine 會變成測試墓地，讓主線 gate 永久失去一部分覆蓋。&lt;/p>
&lt;h2 id="tripwire">Tripwire&lt;/h2>
&lt;p>Tripwire 的責任是提示 flaky 已經從局部問題變成流程問題。&lt;/p>
&lt;ul>
&lt;li>團隊看到紅燈第一反應是 rerun：暫停重跑習慣，要求先分類失敗。&lt;/li>
&lt;li>同一測試一週內多次 quarantine：提升到測試架構或產品 race 檢討。&lt;/li>
&lt;li>Required checks 常因環境問題失敗：檢查 runner、resource、cache 與外部依賴。&lt;/li>
&lt;li>Flaky issue 沒 owner 或沒期限：把 quarantine 視為未完成修復，不視為已處理。&lt;/li>
&lt;/ul>
&lt;h2 id="下一步路由">下一步路由&lt;/h2>
&lt;ul>
&lt;li>Flaky 術語：讀 &lt;a href="https://tarrragon.github.io/blog/ci/knowledge-cards/flaky-test/" data-link-title="Flaky Test" data-link-desc="說明非決定性測試如何降低 CI gate 信任度與治理方式">Flaky Test&lt;/a>。&lt;/li>
&lt;li>Failure routing：讀 &lt;a href="../github-actions-failure-flow/">CI 失敗到修復發布流程&lt;/a>。&lt;/li>
&lt;li>Gate 邊界：讀 &lt;a href="../ci-gate-workflow-boundary/">CI gate 與 workflow 邊界&lt;/a>。&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>Flaky test 治理的核心責任是保護 CI gate 的信任度。<a href="/blog/ci/knowledge-cards/flaky-test/" data-link-title="Flaky Test" data-link-desc="說明非決定性測試如何降低 CI gate 信任度與治理方式">Flaky test</a> 會讓團隊開始用重跑取代判讀，最後讓紅燈失去阻擋意義。</p>
<h2 id="概念定位">概念定位</h2>
<p>Flaky test 是非決定性的 gate 訊號。它的危害不只在延遲 merge，而是在心理上訓練團隊忽略紅燈；當真回歸出現時，大家也可能先按 rerun。治理目標是把 flaky 分類、隔離、修復，並保持 required checks 的語意可信。</p>
<table>
  <thead>
      <tr>
          <th>階段</th>
          <th>責任</th>
          <th>判讀訊號</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Detect</td>
          <td>找出非決定性失敗</td>
          <td>同 commit 重跑結果不一致</td>
      </tr>
      <tr>
          <td>Classify</td>
          <td>區分測試、環境、資料與產品問題</td>
          <td>failure pattern、log、trace</td>
      </tr>
      <tr>
          <td>Contain</td>
          <td>降低對主線 gate 的污染</td>
          <td>quarantine、owner、expiry</td>
      </tr>
      <tr>
          <td>Fix</td>
          <td>修掉根因</td>
          <td>timing、isolation、mock、resource</td>
      </tr>
      <tr>
          <td>Re-admit</td>
          <td>恢復 gate 信任</td>
          <td>連續穩定、觀測窗口、owner sign-off</td>
      </tr>
  </tbody>
</table>
<p>Detect 階段負責證明 flakiness。單次失敗不應直接貼 flaky 標籤；要看同一 commit、同一測試、相近環境下是否出現 pass / fail 不一致，並保存 log、trace、screenshot 或 seed。</p>
<p>Classify 階段負責找根因方向。常見來源包含時間競態、測試順序依賴、共享狀態、外部服務、隨機資料、資源不足、瀏覽器 layout timing、網路模擬與 CI runner 差異；不同來源需要不同修法。</p>
<p>Contain 階段負責保護主線。高價值但暫時 flaky 的測試可以進 quarantine workflow，但必須有 owner、issue、到期日與 replacement gate；直接從 required checks 移除而不追蹤，等於降低品質基線。</p>
<p>Fix 階段負責消除非決定性。常見修法是移除固定 sleep、改用可觀察條件等待、隔離資料、固定 random seed、避免測試共享全域狀態、mock 不穩定外部依賴或調整資源限制。</p>
<p>Re-admit 階段負責把測試放回 gate。測試修完後應在多次 workflow、不同 runner 或足夠時間窗口中穩定通過，再恢復 required checks；否則 gate 會反覆被污染。</p>
<h2 id="分類矩陣">分類矩陣</h2>
<p>分類矩陣的責任是讓 flaky issue 有明確修復路由。沒有分類時，團隊容易只留下「偶發失敗」這種不可執行標籤。</p>
<table>
  <thead>
      <tr>
          <th>類型</th>
          <th>常見訊號</th>
          <th>修復方向</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Timing</td>
          <td>sleep 不足、元素尚未出現</td>
          <td>等待可觀察條件、移除固定 sleep</td>
      </tr>
      <tr>
          <td>Shared state</td>
          <td>單跑通過、整批失敗</td>
          <td>隔離資料、清理全域狀態</td>
      </tr>
      <tr>
          <td>Order</td>
          <td>測試順序改變後失敗</td>
          <td>移除順序依賴、獨立 setup</td>
      </tr>
      <tr>
          <td>External</td>
          <td>第三方 API、網路或時間服務不穩</td>
          <td>mock、contract fixture、retry boundary</td>
      </tr>
      <tr>
          <td>Resource</td>
          <td>CI runner 負載高時失敗</td>
          <td>降低 parallelism、設定 resource</td>
      </tr>
      <tr>
          <td>Product race</td>
          <td>真實功能存在競態</td>
          <td>回到產品修復，不只改測試</td>
      </tr>
  </tbody>
</table>
<p>這張表的邊界是：flaky 可能來自測試，也可能來自產品 race condition。若測試揭露的是產品 race condition，它應該被當成真 bug 處理。</p>
<h2 id="quarantine-契約">Quarantine 契約</h2>
<p>Quarantine 的責任是暫時隔離污染，並維持 gate 的長期品質基線。隔離測試時，要把責任、期限與替代風險控制寫清楚。</p>
<ol>
<li>每個 quarantine test 必須有 issue 與 owner。</li>
<li>每個 issue 必須標明分類、失敗證據與修復方向。</li>
<li>Required checks 若移除測試，要補 replacement gate 或風險說明。</li>
<li>Quarantine workflow 仍需定期跑，並回報趨勢。</li>
<li>到期未修復時要重新評估：修、刪、改寫或降級測試責任。</li>
</ol>
<p>這個契約讓 quarantine 成為治理工具。沒有期限與 owner 的 quarantine 會變成測試墓地，讓主線 gate 永久失去一部分覆蓋。</p>
<h2 id="tripwire">Tripwire</h2>
<p>Tripwire 的責任是提示 flaky 已經從局部問題變成流程問題。</p>
<ul>
<li>團隊看到紅燈第一反應是 rerun：暫停重跑習慣，要求先分類失敗。</li>
<li>同一測試一週內多次 quarantine：提升到測試架構或產品 race 檢討。</li>
<li>Required checks 常因環境問題失敗：檢查 runner、resource、cache 與外部依賴。</li>
<li>Flaky issue 沒 owner 或沒期限：把 quarantine 視為未完成修復，不視為已處理。</li>
</ul>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>Flaky 術語：讀 <a href="/blog/ci/knowledge-cards/flaky-test/" data-link-title="Flaky Test" data-link-desc="說明非決定性測試如何降低 CI gate 信任度與治理方式">Flaky Test</a>。</li>
<li>Failure routing：讀 <a href="../github-actions-failure-flow/">CI 失敗到修復發布流程</a>。</li>
<li>Gate 邊界：讀 <a href="../ci-gate-workflow-boundary/">CI gate 與 workflow 邊界</a>。</li>
</ul>
]]></content:encoded></item></channel></rss>