跳到內容

黃金檔測試

Spec: ISO/IEC/IEEE 29119-4 Spec: ISO/IEC 25010 Evidence: Test-backed

黃金檔是一份記錄下來的「正確輸出應該長這樣」,測試每次執行時都會拿它來比對。NextPDF 用黃金檔捕捉非預期變更:壓縮方式不同的串流、位置移動的段落、偏移的座標。本頁說明這套機制如何運作,以及黃金檔如何保持值得信賴,而不是淪為一份沒有人讀的過時參考。

PDF 產生是一條很長的管線,有許多地方可能悄悄偏移。一次「什麼都沒改」的重構,可能不知不覺重排了運算子、改動了一個變換矩陣,或讓某個表格儲存格產生極小的偏移。單元測試很少能捕捉這種情況:它們斷言的是你想到要檢查的某個值,而不是那些你沒有檢查的數千個位元組。以結構為基礎與以規格為基礎的技術會偵測到不同錯誤,兩者都無法完整涵蓋對方(ISO/IEC/IEEE 29119-4,附錄 A)。黃金檔正是一份以範例呈現的規格,它釘選的是整份輸出,而非單一個斷言。

風險是雙向的。太嚴格的黃金檔會碰到每個無害變更都失敗,然後被盲目重新核可,直到它什麼也證明不了。太寬鬆的黃金檔則會讓真正的回歸通過。拿捏好這個平衡,正是這門手藝的全部。

  • 黃金檔是一份釘選的參考輸出,由已知良好的引擎行為產生,並提交到版本庫中。
  • 黃金測試會重新產生輸出,並將它與釘選的參考相比對;任何差異都會讓測試失敗,並要求由人判斷。
  • NextPDF 在有意義且穩定的層級上比對:擷取出的文字與正規化後的結構運算子,而非原始位元組,因為原始位元組帶有雜訊(時間戳、子集排序、壓縮),那些並不是回歸。
  • 更新黃金檔是一個刻意且經過審查的動作,受明確的 GOLDEN_UPDATE 開關控管——絕不是自動「接受任何變更」。
  • 黃金測試與快照測試、特性化測試有一個決定性的差別:黃金檔永不自動更新

引擎的黃金檔基礎設施採用明確的雙層比對,而非位元組比對:

  1. Generate Render the fixture input through the current engine.
  2. Layer 1 — text Extract human-readable text from the content stream; diff against the text golden. Catches dropped or reordered content and encoding regressions.
  3. Layer 2 — structure Extract ordered PDF operators, normalise coordinates to a fixed precision, diff against the operator golden. Catches layout shifts and broken structure.
  4. Decide Any diff fails the test; a human judges whether it is a regression or an intended change.
一次 NextPDF 黃金比對的執行方式:產生 PDF,擷取有意義的層(先是文字,再是正規化後的結構運算子),將每一層與釘選的參考相比對,並在出現任何差異時以人類可讀的報告失敗。

它刻意比對的內容,和它實際比對的內容一樣重要。原始位元組輸出被排除在外,因為時間戳、字型子集排序與串流壓縮會讓它變得脆弱,卻不會讓它更正確。像素層級的影像比對在這一層被排除在外,因為它需要外部算繪器,並會引入環境差異。浮點座標會被正規化到固定精度,避免無意義的捨入雜訊偽裝成回歸。這就是測試行為的黃金檔,與測試短暫環境雜訊的黃金檔之間的差別。

這項選擇也決定了本頁標示的可重現性設定:結構性。NextPDF 記載了三種設定——逐位元(精確的位元組可重現)、結構性(物件圖與運算子序列可重現,允許良性的位元組層級差異)以及語意(意義可重現)。這一層的黃金測試在設計上斷言的就是結構性設定。這就是為什麼它們的參考能在一次壓縮函式庫升級後存活,卻仍會在一個移動過的表格上失敗。

Evidence: Test-backed 這套雙層比對(先擷取文字, 再比對正規化後的結構運算子)是引擎自身記載的黃金檔方法論,並基於上述理由,明確將原始位元組、影像比對與精確浮點比對排除在範圍之外。黃金套件是一個經宣告、可獨立執行的測試套件,有別於快照與特性化套件。

Evidence: Test-backed 誠實機制很具體: 黃金參考是產生出來的成品,而非手寫而成。覆寫它們的動作,受一個明確的 GOLDEN_UPDATE 環境開關把關,該開關記載為一個罕見、永遠經過審查的操作。相較之下,引擎中的快照測試會在首次執行時重新產生,並透過更新旗標來確認偏移。而特性化測試則鎖定既有行為,卻不主張它是正確的。這三者是刻意設計成不同的工具。

Evidence: Standard-backed 黃金檔是一份以範例呈現的規格。 Spec: ISO/IEC/IEEE 29119-4, Annex A 指出以規格為基礎與以結構為基礎的技術會捕捉不同類別的錯誤,而一套策略應該將它們結合起來。這就是為什麼在 測試金字塔中,黃金檔是與單元測試和結構測試並列,而非取而代之。

黃金測試在機制上很簡單;紀律在於圍繞它的工作流程:

<?php
declare(strict_types=1);
// 1. The fixture: a fixed HTML input committed next to the test.
// tests/Golden/fixtures/html-inputs/002-basic-table.html
// 2. The pinned references, generated once from known-good behaviour:
// 002-basic-table.text.golden (Layer 1 — extracted text)
// 002-basic-table.operators.golden (Layer 2 — normalised operators)
// 3. The run compares; ANY difference fails:
// vendor/bin/phpunit --testsuite Golden
// 4. An intended behaviour change is the ONLY time references move,
// and it is explicit and reviewed — never automatic:
// GOLDEN_UPDATE=1 vendor/bin/phpunit --testsuite Golden
//
// The regenerated *.golden files land in the diff of the same change
// that altered behaviour, so a reviewer sees the output delta next to
// the code delta and signs off on both together.

範例本身展示的就是流程。測試程式碼只負責比對。讓黃金檔值得信賴的,是在同一個改動引擎的變更中,把更新後的參考當作輸出一併審查。

最常見的錯誤,是把黃金測試當成逐位元組測試。NextPDF 的黃金檔並不是檔案位元組本身——而是它擷取出的文字與正規化後的結構運算子。斷言原始位元組會在新版 zlib、不同的子集標籤或重新產生的時間戳上失敗,而這些都不是回歸。接著這個測試會在一週之內被重新核可到毫無用處。(當精確的位元組確實必須可重現時,那屬於另一個獨立、更嚴格的逐位元可重現性設定,而非黃金檔。)

第二個錯誤,是假設一套全綠的黃金套件就證明了正確性。它證明的是未變更。從有缺陷的輸出產生的黃金檔,會忠實地保護那個缺陷。黃金檔防範的是從已知良好基準線發生的回歸;它們並不確立那條基準線當初是好的。那是單元、結構與符合性各層的職責。

黃金測試只回答一個問題:輸出相對於釘選的參考是否發生了變化。它不說明那份參考當初是否正確。它也不衡量效能、符合性或安全性。那些是其他層的事。夾具語料庫的大小、套件的通過率,以及任何覆蓋率數字,都是從持續整合成品產生、並隨建置一同發布的活躍品質訊號。本文刻意不在這裡列出它們,以免在此處變得過時。

確切的目錄佈局、比對器內部運作與更新開關,由引擎的測試基礎設施所擁有,並可能演進。若測試組態與本說明有任何牴觸,以測試組態為準。本頁不對任何其他函式庫的快照或黃金工具做任何主張。

  • NextPDF 測試金字塔——黃金層在這五層中的位置,以及它獨有的證明範圍。
  • 變異測試解析——NextPDF 如何檢查它的測試(含黃金檔)是否真的能偵測到缺陷。
  • 處處嚴格型別——在任何黃金測試執行之前,就先移除一整類缺陷的靜態分析。
  • 黃金檔——一份釘選的參考輸出,由已知良好的引擎行為產生並提交,測試每次執行時都會拿它來比對。永不自動更新。
  • 雙層比對——NextPDF 的黃金比對:擷取出的文字(第 1 層)加上正規化後的結構運算子(第 2 層),而非原始位元組。
  • 快照測試——一種相關但不同的技術,其參考會在首次執行時重新產生,並透過更新旗標來確認偏移。
  • 特性化測試——一種鎖定既有行為、卻不斷言其正確性的測試,通常用來讓重構變得安全。
  • 可重現性設定——輸出必須重現的層級:逐位元(精確的位元組)、結構性(物件圖與運算子序列,允許良性的位元組差異),或語意(意義)。此處的黃金測試斷言的是結構性設定。
  • GOLDEN_UPDATE——用來授權覆寫黃金參考的明確環境開關;一個罕見、經過審查的操作。