ข้ามไปยังเนื้อหา

การทดสอบด้วย Golden file

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

Golden file คือบันทึกที่ระบุว่า “เอาต์พุตที่ถูกต้องมีลักษณะอย่างไร” ซึ่งการทดสอบใช้เปรียบเทียบทุกครั้งที่รัน NextPDF ใช้ golden เพื่อตรวจจับการเปลี่ยนแปลงที่ไม่ได้ตั้งใจ เช่น สตรีมที่ถูกบีบอัดต่างไป ย่อหน้าที่ขยับตำแหน่ง หรือพิกัดที่คลาดเคลื่อนไป หน้านี้อธิบายว่ากระบวนการดังกล่าวทำงานอย่างไร และทำให้ golden ยังคงน่าเชื่อถือได้อย่างไรแทนที่จะกลายเป็นการอ้างอิงที่ล้าสมัยซึ่งไม่มีใครอ่าน

การสร้าง PDF เป็นไปป์ไลน์ที่ยาว ซึ่งมีจุดมากมายที่อาจคลาดเคลื่อนไปอย่างเงียบๆ การรีแฟกเตอร์ที่ “ไม่ได้เปลี่ยนแปลงอะไร” อาจจัดลำดับโอเปอเรเตอร์ใหม่ เปลี่ยน transform matrix หรือขยับเซลล์ในตารางไปเล็กน้อยอย่างเงียบๆ Unit test มักจับสิ่งนี้ไม่ได้ เพราะตรวจยืนยันเฉพาะค่าที่ผู้เขียนนึกถึงว่าจะตรวจ ไม่ใช่ไบต์อีกหลายพันไบต์ที่ไม่ได้ตรวจ เทคนิคที่อิงโครงสร้างและที่อิงข้อกำหนดตรวจพบข้อผิดพลาดคนละแบบ และไม่มีเทคนิคใดครอบคลุมอีกเทคนิคหนึ่งได้ (ISO/IEC/IEEE 29119-4, Annex A) Golden file คือข้อกำหนดในรูปแบบตัวอย่างที่ตรึงเอาต์พุต ทั้งหมด ไว้ ไม่ใช่การตรวจยืนยันเพียงข้อเดียว

ความเสี่ยงเกิดขึ้นได้ทั้งสองทาง Golden ที่เข้มงวดเกินไปจะล้มเหลวกับทุกการเปลี่ยนแปลงที่ไม่เป็นอันตราย และถูกอนุมัติใหม่แบบไม่ใส่ใจจนพิสูจน์อะไรไม่ได้เลย Golden ที่หละหลวมเกินไปจะปล่อยให้การถดถอยที่แท้จริงผ่านไปได้ การหาจุดสมดุลให้พอดีคือหัวใจของแนวทางนี้

  • Golden file คือเอาต์พุตอ้างอิงที่ตรึงไว้ ซึ่งสร้างขึ้นจากพฤติกรรมของเอนจินที่ทราบแล้วว่าถูกต้อง และคอมมิตเข้าสู่ repository
  • Golden test จะสร้างเอาต์พุตขึ้นใหม่และ เปรียบเทียบความแตกต่างกับการอ้างอิงที่ตรึงไว้ ความแตกต่างใดๆ จะทำให้การทดสอบล้มเหลวและต้องอาศัยการตัดสินใจจากมนุษย์
  • NextPDF เปรียบเทียบที่ระดับซึ่ง มีความหมายและเสถียร ได้แก่ ข้อความที่สกัดออกมาและโอเปอเรเตอร์เชิงโครงสร้างที่ทำให้เป็นมาตรฐานแล้ว ไม่ใช่ไบต์ดิบ เพราะไบต์ดิบมีสัญญาณรบกวน (ไทม์สแตมป์ ลำดับของซับเซ็ต การบีบอัด) ซึ่งไม่ใช่การถดถอย
  • การอัปเดต golden เป็นการดำเนินการโดยเจตนาและผ่านการตรวจทาน โดยอยู่หลังสวิตช์ GOLDEN_UPDATE ที่ระบุไว้อย่างชัดเจน ไม่ใช่การ “ยอมรับสิ่งใดก็ตามที่เปลี่ยนไป” โดยอัตโนมัติ
  • Golden แตกต่างจากการทดสอบแบบ snapshot และ characterization ในจุดสำคัญหนึ่งจุด คือ golden จะ ไม่อัปเดตโดยอัตโนมัติ โดยเด็ดขาด

โครงสร้างพื้นฐานสำหรับ golden ในเอนจินใช้ การเปรียบเทียบความแตกต่างสองชั้น ที่ระบุไว้อย่างชัดเจน แทนการเปรียบเทียบแบบไบต์ต่อไบต์

  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.
วิธีที่การเปรียบเทียบ golden ของ NextPDF ทำงาน ได้แก่ สร้าง PDF สกัดชั้นที่มีความหมายออกมา (ข้อความ จากนั้นโอเปอเรเตอร์เชิงโครงสร้างที่ทำให้เป็นมาตรฐานแล้ว) เปรียบเทียบความแตกต่างของแต่ละชั้นกับการอ้างอิงที่ตรึงไว้ และแสดงความล้มเหลวพร้อมรายงานที่มนุษย์อ่านได้เมื่อมีความแตกต่างใด ๆ

สิ่งที่จงใจ ไม่ นำมาเปรียบเทียบมีความสำคัญเท่ากับสิ่งที่นำมาเปรียบเทียบ เอาต์พุตแบบไบต์ดิบถูกตัดออกไป เพราะไทม์สแตมป์ ลำดับของฟอนต์ซับเซ็ต และการบีบอัดสตรีมเพิ่มความเปราะบางโดยไม่ได้เพิ่มความถูกต้อง การเปรียบเทียบภาพในระดับพิกเซลถูกตัดออกจากชั้นนี้ เพราะต้องใช้ตัวเรนเดอร์ภายนอกและนำความผันแปรของสภาพแวดล้อมเข้ามา พิกัดแบบ floating-point จะถูกทำให้เป็นมาตรฐานที่ความแม่นยำคงที่ เพื่อไม่ให้สัญญาณรบกวนจากการปัดเศษที่ไร้ความหมายถูกเข้าใจผิดว่าเป็นการถดถอย นี่คือความแตกต่างระหว่าง golden ที่ทดสอบ พฤติกรรม กับ golden ที่ทดสอบ สัญญาณรบกวนชั่วคราวของสภาพแวดล้อม นั่นเอง

การเลือกเช่นนี้ยังระบุโปรไฟล์ความสามารถในการทำซ้ำของหน้านี้ด้วย คือ structural NextPDF จัดทำเอกสารโปรไฟล์ไว้สามแบบ ได้แก่ bitwise (ไบต์ที่เหมือนกันทุกประการทำซ้ำได้) structural (กราฟของออบเจกต์และลำดับโอเปอเรเตอร์ทำซ้ำได้ โดยอนุญาตให้มีความผันแปรในระดับไบต์ที่ไม่เป็นอันตราย) และ semantic (ความหมายทำซ้ำได้) Golden test ในชั้นนี้ตรวจยืนยันโปรไฟล์ structural โดยการออกแบบ นั่นคือเหตุผลที่การอ้างอิงเหล่านี้ยังอยู่รอดเมื่อมีการอัปเกรดไลบรารีบีบอัด แต่ยังคงล้มเหลวเมื่อตารางถูกขยับ

Evidence: Test-backed การเปรียบเทียบสองชั้น (การสกัด ข้อความ จากนั้นการเปรียบเทียบโอเปอเรเตอร์เชิงโครงสร้างที่ทำให้เป็นมาตรฐานแล้ว) คือ วิธีการ golden ที่เอนจินจัดทำเอกสารไว้เอง โดยการเปรียบเทียบแบบไบต์ดิบ การเปรียบเทียบภาพ และการเปรียบเทียบค่า float แบบเป๊ะๆ อยู่นอกขอบเขตอย่างชัดเจนด้วยเหตุผลข้างต้น ชุดทดสอบ golden เป็น ชุดทดสอบที่ประกาศไว้และรันแยกได้ ซึ่งแตกต่างจากชุดทดสอบ snapshot และ characterization

Evidence: Test-backed กลไกรักษาความน่าเชื่อถือนั้นเป็นรูปธรรม การอ้างอิง golden เป็นสิ่งที่สร้างขึ้น ไม่ใช่เขียนด้วยมือ การเขียนทับ การอ้างอิงเหล่านั้นถูกควบคุมด้วยสวิตช์สภาพแวดล้อม GOLDEN_UPDATE ที่ระบุไว้อย่างชัดเจน ซึ่งจัดทำเอกสารไว้ ในฐานะการดำเนินการที่เกิดขึ้นไม่บ่อยและผ่านการตรวจทานเสมอ ในทางตรงกันข้าม การทดสอบ snapshot ใน เอนจินจะสร้างขึ้นใหม่ในการรันครั้งแรกและรับรู้การเปลี่ยนแปลงผ่านแฟล็กอัปเดต และ การทดสอบ characterization จะตรึงพฤติกรรมเดิมไว้โดยไม่ได้อ้างว่าพฤติกรรมนั้น ถูกต้อง ทั้งสามอย่างเป็นเครื่องมือที่ถูกออกแบบให้แตกต่างกันโดยเจตนา

Evidence: Standard-backed Golden คือ ข้อกำหนดในรูปแบบตัวอย่าง Spec: ISO/IEC/IEEE 29119-4, Annex A ระบุว่าเทคนิคที่อิงข้อกำหนดและที่อิงโครงสร้างจับข้อผิดพลาด คนละกลุ่ม และกลยุทธ์ควรนำทั้งสองมารวมกัน นั่นคือเหตุผลที่ golden อยู่เคียงข้างการทดสอบ unit และ structural ใน testing pyramid นั่นเอง

ในเชิงกลไก Golden test นั้นเรียบง่าย วินัยที่สำคัญอยู่ในเวิร์กโฟลว์รอบๆการทดสอบนั้น

<?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.

ตัวอย่างนี้แสดงกระบวนการ โค้ดของการทดสอบทำเพียงเปรียบเทียบความแตกต่างเท่านั้น สิ่งที่ทำให้ golden น่าเชื่อถือคือการอ้างอิงที่เปลี่ยนไปจะถูกตรวจทาน ในฐานะเอาต์พุต ภายในการเปลี่ยนแปลงเดียวกับที่แก้ไขเอนจิน

ความผิดพลาดที่พบบ่อยที่สุดคือการมองการทดสอบ golden ว่าเป็นการทดสอบแบบไบต์ต่อไบต์ Golden ของ NextPDF ไม่ใช่ไบต์ดิบของไฟล์ แต่เป็นข้อความที่สกัดออกมาและโอเปอเรเตอร์เชิงโครงสร้างที่ทำให้เป็นมาตรฐานแล้วของไฟล์นั้น การตรวจยืนยันไบต์ดิบจะล้มเหลวเมื่อมี zlib เวอร์ชันใหม่ แท็กซับเซ็ตที่ต่างไป หรือไทม์สแตมป์ที่สร้างขึ้นใหม่ ซึ่งล้วนไม่ใช่การถดถอย การทดสอบจะถูกอนุมัติใหม่จนหมดประโยชน์ภายในหนึ่งสัปดาห์ (ในกรณีที่ไบต์ที่เหมือนกันทุกประการต้องทำซ้ำได้จริงๆ นั่นคือโปรไฟล์ความสามารถในการทำซ้ำ bitwise ที่แยกต่างหากและเข้มงวดกว่า ไม่ใช่ golden)

ความผิดพลาดข้อที่สองคือการสันนิษฐานว่าชุดทดสอบ golden ที่ผ่าน (สีเขียว) พิสูจน์ความถูกต้อง สิ่งที่พิสูจน์ได้คือ การไม่เปลี่ยนแปลง Golden ที่สร้างขึ้นจากเอาต์พุตที่มีบั๊กจะตรึงบั๊กนั้นไว้อย่างซื่อสัตย์ Golden ป้องกันการถดถอยจากเส้นฐานที่ทราบแล้วว่าถูกต้อง แต่ไม่ได้ยืนยันว่าเส้นฐานนั้นถูกต้องจริง นั่นคือหน้าที่ของชั้น unit, structural และ conformance

Golden test ตอบคำถามเพียงข้อเดียวเท่านั้น คือเอาต์พุตเปลี่ยนไปจากการอ้างอิงที่ตรึงไว้หรือไม่ การทดสอบไม่ได้บอกว่าการอ้างอิงนั้นเคยถูกต้องหรือไม่ ทั้งยังไม่ได้วัดประสิทธิภาพ ความสอดคล้องตามมาตรฐาน หรือความปลอดภัย สิ่งเหล่านั้นเป็นหน้าที่ของชั้นอื่น ขนาดของคลังฟิกซ์เจอร์ อัตราการผ่านของชุดทดสอบ และตัวเลขความครอบคลุมใดๆ เป็นสัญญาณคุณภาพที่มีการเปลี่ยนแปลงตลอดเวลา ซึ่งสร้างขึ้นจากอาร์ติแฟกต์ของ continuous integration และเผยแพร่พร้อมกับบิลด์ ค่าเหล่านี้จึงจงใจไม่ระบุไว้ที่นี่ เพราะอาจล้าสมัยได้

เค้าโครงไดเรกทอรีที่แน่นอน รายละเอียดภายในของตัวเปรียบเทียบ และสวิตช์อัปเดต เป็นของโครงสร้างพื้นฐานการทดสอบของเอนจินและอาจเปลี่ยนแปลงได้ การกำหนดค่าการทดสอบถือเป็นแหล่งอ้างอิงที่มีอำนาจหากขัดแย้งกับคำอธิบายนี้ หน้านี้ไม่ได้กล่าวอ้างใดๆ เกี่ยวกับเครื่องมือ snapshot หรือ golden ของไลบรารีอื่น

  • พีระมิดการทดสอบของ NextPDF — ตำแหน่งของชั้น golden ในทั้งห้าชั้น และสิ่งที่ชั้นนี้พิสูจน์ได้อย่างเป็นเอกลักษณ์
  • Mutation testing, explained — วิธีที่ NextPDF ตรวจสอบว่าการทดสอบของตน รวมถึง golden ตรวจพบข้อบกพร่องได้จริง
  • Strict types, everywhere — การวิเคราะห์แบบสถิตที่ขจัดข้อบกพร่องกลุ่มหนึ่งออกไปก่อนที่ golden ใดๆ จะรัน
  • Golden file — เอาต์พุตอ้างอิงที่ตรึงไว้ ซึ่งสร้างขึ้นจากพฤติกรรมของเอนจินที่ทราบแล้วว่าถูกต้องและคอมมิตไว้ โดยการทดสอบจะนำมาเปรียบเทียบความแตกต่างทุกครั้งที่รัน ไม่อัปเดตโดยอัตโนมัติเด็ดขาด
  • Two-layer diff — การเปรียบเทียบ golden ของ NextPDF ได้แก่ ข้อความที่สกัดออกมา (Layer 1) ร่วมกับโอเปอเรเตอร์เชิงโครงสร้างที่ทำให้เป็นมาตรฐานแล้ว (Layer 2) แทนการใช้ไบต์ดิบ
  • Snapshot test — เทคนิคที่เกี่ยวข้องแต่แตกต่าง ซึ่งการอ้างอิงจะถูกสร้างขึ้นใหม่ในการรันครั้งแรกและรับรู้การเปลี่ยนแปลงผ่านแฟล็กอัปเดต
  • Characterization test — การทดสอบที่ตรึงพฤติกรรมที่มีอยู่เดิมไว้โดยไม่ได้ตรวจยืนยันว่าถูกต้อง โดยทั่วไปทำเพื่อให้การรีแฟกเตอร์ปลอดภัย
  • Reproducibility profile — ระดับที่เอาต์พุตต้องทำซ้ำได้ ได้แก่ bitwise (ไบต์ที่เหมือนกันทุกประการ) structural (กราฟของออบเจกต์และลำดับโอเปอเรเตอร์ โดยอนุญาตให้มีความผันแปรในระดับไบต์ที่ไม่เป็นอันตราย) หรือ semantic (ความหมาย) Golden test ในที่นี้ตรวจยืนยันโปรไฟล์ structural
  • GOLDEN_UPDATE — สวิตช์สภาพแวดล้อมที่ระบุไว้อย่างชัดเจน ซึ่งอนุญาตให้เขียนทับการอ้างอิง golden ได้ โดยเป็นการดำเนินการที่เกิดขึ้นไม่บ่อยและผ่านการตรวจทาน