黄金文件测试
Spec: ISO/IEC/IEEE 29119-4 ISO/IEC/IEEE 29119-4 Spec: ISO/IEC 25010 ISO/IEC 25010 Evidence: Test-backed
黄金文件记录了一份「正确输出应该是什么样子」。每次测试运行时,都会用它进行比对。NextPDF 使用黄金文件捕捉并非有意引入的变更:压缩方式不同的流、位置移动的段落、坐标发生偏移的对象。本页说明它的工作方式,以及黄金文件如何保持可信,而不是沦为无人阅读的过时参考。
为什么这很重要
标题为“为什么这很重要”的章节PDF 生成是一条很长的流水线,许多位置都可能悄然发生偏移。一次「什么都没改」的重构,可能在不知不觉中重排了运算符、改动了一个变换矩阵,或让某个表格单元格发生极小偏移。单元测试很少能捕捉这种情况:它们断言的是你想到要检查的某个值,而不是那数千个你没有检查的字节。基于结构与基于规格的技术会侦测到不同类型的错误,两者谁也无法覆盖对方(ISO/IEC/IEEE 29119-4,附录 A)。黄金文件正是以示例形式存在的规格,它固定的是整份输出,而不是单个断言。
风险有两面。过于严格的黄金文件会在每一个无害变更上失败,然后被盲目重新批准,直到它什么也证明不了。过于宽松的黄金文件则会让真正的回归通过。把握好这个平衡,正是这门手艺的全部。
精简版说明
标题为“精简版说明”的章节- 黄金文件是一份固定的参考输出,由已知良好的引擎行为产生,并提交到版本库中。
- 黄金测试会重新生成输出,并将它与固定的参考进行比对;任何差异都会让测试失败,并要求由人做出决定。
- NextPDF 在有意义且稳定的层级进行比对:提取出的文本与规范化后的结构运算符,而不是原始字节,因为原始字节包含噪声(时间戳、子集排序、压缩),这些并不是回归。
- 更新黄金文件是一项刻意且经过审查的操作,放在明确的
GOLDEN_UPDATE开关之后——绝不是自动「接受任何变更」。 - 黄金测试与快照测试、特性化测试有一个关键差别:黄金文件永不自动更新。
NextPDF 的做法
标题为“NextPDF 的做法”的章节引擎的黄金文件基础设施采用明确的双层比对,而不是字节比对:
- Generate Render the fixture input through the current engine.
- Layer 1 — text Extract human-readable text from the content stream; diff against the text golden. Catches dropped or reordered content and encoding regressions.
- Layer 2 — structure Extract ordered PDF operators, normalise coordinates to a fixed precision, diff against the operator golden. Catches layout shifts and broken structure.
- Decide Any diff fails the test; a human judges whether it is a regression or an intended change.
它刻意不比对的内容,和它实际比对的内容一样重要。原始字节输出被排除在外,因为时间戳、字体子集排序与流压缩会让它变得脆弱,却不会让它更正确。像素级图像比对也被排除在这一层之外,因为它需要外部渲染器,并会引入环境差异。浮点坐标会规范化到固定精度,让无意义的舍入噪声不会伪装成回归。这就是测试行为的黄金文件,与测试瞬时环境噪声的黄金文件之间的差别。
这个选择也解释了本页为什么把可重现性设置命名为:结构性。NextPDF 记录了三种设置——逐比特(精确的字节可重现)、结构性(对象图与运算符序列可重现,允许良性的字节级差异)以及语义(意义可重现)。这一层的黄金测试在设计上断言的就是结构性设置。这就是为什么这些参考能在一次压缩库升级后继续有效,却仍会在表格被移动时失败。
证据怎么说
标题为“证据怎么说”的章节Evidence: Test-backed 这套双层比对(先提取文本, 再比对规范化后的结构运算符)是引擎自身记录的黄金文件方法论。基于上述理由,它明确将原始字节、图像比对与精确浮点比对排除在范围之外。黄金套件是一套经声明、可独立运行的测试套件,区别于快照与特性化套件。
Evidence: Test-backed 可信机制很具体:
黄金参考是生成出来的成品,而不是手写的。覆盖它们的操作由一个明确的 GOLDEN_UPDATE 环境开关把关,该开关被记录为一项罕见、始终经过审查的操作。相比之下,引擎中的快照测试会在首次运行时重新生成,并通过一个更新标志来确认偏移。而特性化测试则锁定既有行为,却不主张它是正确的。这三者是刻意设计成不同的工具。
Evidence: Standard-backed 黄金文件是一份以示例形式存在的规格。 Spec: ISO/IEC/IEEE 29119-4, Annex A 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——授权覆盖黄金参考的明确环境开关;一项罕见、经过审查的操作。