Ir al contenido

La pirámide de pruebas de NextPDF

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

NextPDF no se apoya en un único tipo de prueba. Usa cinco niveles, y cada uno responde a una pregunta distinta sobre el motor. La razón es que un PDF puede pasar una prueba unitaria y, aun así, ser un archivo estructuralmente roto en disco. Esta página nombra los cinco niveles y explica qué debe demostrar cada uno.

Un motor PDF tiene una superficie de fallo inusualmente amplia. La misma ruta de ejecución puede ser correcta como función y como flujo de bytes, y aun así producir un archivo que un lector conforme rechaza. También puede producir un archivo que se representa de forma sutilmente incorrecta solo en un salto de página. Si se prueba el motor con una única granularidad, solo se obtiene confianza en esa granularidad y en nada más.

La literatura normativa es clara al respecto. Las técnicas de diseño de pruebas basadas en la especificación y las basadas en la estructura no guardan relación entre sí, y se recomienda que una estrategia de pruebas use más de un criterio, con al menos uno funcional y uno estructural (ISO/IEC/IEEE 29119-4, Anexo A). Un único nivel no es una versión reducida de una buena estrategia. Es una estrategia distinta y, además, incompleta.

Las pruebas de NextPDF se organizan en cinco niveles, de la base al vértice:

  1. Unitario — una clase o función, de forma aislada. La base amplia.
  2. Integración — unidades que colaboran a través de un límite de módulo.
  3. Estructural — el grafo de objetos del PDF emitido, la tabla de referencias cruzadas y el tráiler están bien formados y son conformes.
  4. Visual — la página representada coincide con una referencia aprobada dentro de una tolerancia declarada.
  5. De referencia (golden) — fixtures de extremo a extremo ancladas que detectan desviaciones no deseadas en la salida final. El vértice.

Cada nivel demuestra algo que el nivel inferior no puede. Ninguno es decorativo. La forma de pirámide tiene que ver con la cantidad —muchas pruebas unitarias baratas, menos pruebas de extremo a extremo costosas—, no con la importancia.

Los niveles son concretos, no aspiracionales. La configuración de PHPUnit del repositorio declara cada uno como un conjunto de pruebas con nombre asignado uno a uno a un directorio. Por tanto, un nivel es una ubicación a la que se puede apuntar un ejecutor, no una etiqueta en una diapositiva. Entre los conjuntos de pruebas que reconocería un ingeniero veterano están Unit, Integration, Golden, Snapshot, Reproducibility, Conformance, Standards y Performance, cada uno con su propio perfil de ejecución (aislamiento, presupuesto de tiempo y si se ejecuta de forma predeterminada en la integración continua).

Esa separación es deliberada. El nivel base rápido (Unit) se ejecuta en cada cambio con un presupuesto de un segundo por prueba. Los niveles más lentos y sensibles al entorno —representación visual, conformidad completa, rendimiento— son opcionales o nocturnos. Esto mantiene la ruta habitual rápida y determinista sin renunciar a las comprobaciones más profundas. El tipado estricto sostiene toda la pila. El análisis del motor se ejecuta en Spec: PHPStan, Level 10 con el presupuesto de errores fijado en cero, de modo que una amplia clase de defectos ni siquiera llega a una prueba.

  1. Tier 1 of 5 Unit Isolated behaviour of a single class or function; the broad base.
  2. Tier 2 of 5 Integration Collaborating units across a module boundary.
  3. Tier 3 of 5 Structural The emitted PDF object/xref structure is well-formed and conformant.
  4. Tier 4 of 5 Visual Rendered output matches an approved reference within tolerance.
  5. Tier 5 of 5 Golden End-to-end byte/lossless fixtures pinned as the contract; the apex.
Los cinco niveles de pruebas de NextPDF, de la base al vértice. El unitario es la base amplia y rápida; cada nivel superior demuestra una propiedad que el nivel inferior no puede, hasta llegar a las fixtures de referencia (golden) de extremo a extremo en el vértice. El ancho es solo una pista de cantidad: no clasifica la importancia.

Evidence: Test-backed Los cinco conjuntos existen como conjuntos de pruebas de PHPUnit declarados en la configuración del motor, cada uno vinculado a su propio directorio y perfil de ejecución. La terminología de niveles de esta página es la misma que usa la infraestructura de pruebas.

Evidence: Standard-backed La razón de que haya más de un nivel se fundamenta en Spec: ISO/IEC/IEEE 29119-4, Annex A : no todos los criterios de cobertura guardan relación entre sí, y se recomienda que una estrategia combine técnicas funcionales y estructurales. Es crucial que el mismo anexo señala que el orden de subsunción entre los criterios de cobertura no ofrece ninguna indicación sobre su capacidad para exponer fallos —eficacia de las pruebas (ISO/IEC/IEEE 29119-4, §C.2.4). «Más cobertura» no equivale a «mejores pruebas».

Evidence: Standard-backed La elección de qué propiedades demostrar se alinea con las características de calidad del producto de Spec: ISO/IEC 25010 en cuanto a la corrección funcional (unitario, integración) y las propiedades a nivel de archivo que hacen que un PDF sea realmente utilizable aguas abajo (estructural, visual, de referencia). El modelo de calidad es explícito en que distintas características importan en distintos contextos de uso.

Los niveles son accesibles desde los propios scripts del motor. Un cambio en un solo formateador se comprueba en la base. Un cambio en la fachada del documento se comprueba en varios niveles:

<?php
declare(strict_types=1);
// Tier 1 — Unit: one unit, isolated, fast.
// composer test:unit → phpunit --testsuite Unit
// Tier 2 — Integration: collaborating units across a boundary.
// composer test:integration → phpunit --testsuite Integration
// Tier 3 — Structural: the emitted PDF object graph is well-formed.
// vendor/bin/phpunit --testsuite Conformance
// Tier 4/5 — Visual + Golden: rendered/serialized output vs a pinned
// reference (golden is byte/structure-pinned, never auto-updated).
// vendor/bin/phpunit --testsuite Golden
// A change to the document facade touches every API, so the routing
// guidance escalates it from "unit only" to the full unit + integration
// surface — the tier you run is a function of blast radius, not habit.

El objetivo del ejemplo es la lógica de enrutamiento, no los comandos. El nivel que se ejercita lo determina lo que el cambio puede romper. La infraestructura convierte cada nivel en un objetivo de primera clase, ejecutable por separado.

A menudo la pirámide se interpreta como una clasificación: las pruebas unitarias abajo porque importan menos, las de extremo a extremo arriba porque importan más (o al revés). No es ni lo uno ni lo otro. El eje vertical es, a grandes rasgos, coste y cantidad: muchas pruebas unitarias rápidas y baratas que forman una base amplia; por encima, pruebas progresivamente menos numerosas, más lentas y de mayor fidelidad. Una prueba de referencia (golden) no es «mejor» que una prueba unitaria. Detecta un fallo distinto, más tarde, de forma más costosa, y sería un mal sustituto de las miles de comprobaciones rápidas situadas debajo.

La segunda idea errónea es que un número de cobertura alto significa que la pirámide es sólida. No lo significa. La cobertura mide ejecución, no detección. Las normas no equiparan explícitamente el orden de cobertura con la capacidad de encontrar fallos. Las pruebas de mutación existen precisamente para exponer esa brecha.

Esta página describe la forma y el propósito de la estrategia, no sus resultados actuales. Los recuentos de pruebas, los porcentajes de cobertura y las puntuaciones de mutación están deliberadamente ausentes aquí. Son señales de calidad dinámicas, generadas a partir de artefactos de integración continua. Las cifras actuales se publican con cada compilación. Congeladas en prosa, quedarían silenciosamente desactualizadas. El único número que se indica —PHPStan Level 10— es un dato de configuración estable, verificable en la configuración de análisis estático del motor, no una medición.

Los nombres de los niveles son vocabulario de arquitectura estable. El conjunto preciso de suites y sus perfiles de ejecución evoluciona con el motor y pertenece a la configuración de pruebas, que es la autoridad si alguna vez difiere de esta explicación. Esta página no afirma ninguna tasa de aprobación concreta ni establece comparación alguna con la estrategia de pruebas de ninguna otra biblioteca.

  • Nivel de pruebas — un nivel de la estrategia que demuestra un tipo de propiedad (por ejemplo, comportamiento unitario o validez estructural). NextPDF usa cinco.
  • Prueba estructural — una comprobación de que el grafo de objetos del PDF emitido, la tabla de referencias cruzadas y el tráiler están bien formados y son conformes, en lugar de limitarse a comprobar un valor de retorno.
  • Prueba visual — una comprobación de que una página representada coincide con una imagen de referencia aprobada dentro de una tolerancia declarada.
  • Prueba de referencia (golden) — una comprobación de extremo a extremo contra una salida de referencia anclada que nunca se actualiza de forma automática; el contrato de «la salida no cambió».
  • Eficacia de las pruebas — la capacidad de un conjunto de pruebas para exponer fallos, que ISO/IEC/IEEE 29119-4 distingue de la cobertura. Aclaración sobre la sigla: el MSI (Mutation Score Indicator, indicador de puntuación de mutación) se define en la página de pruebas de mutación.
  • PHPStan Level 10 — el nivel de análisis estático más estricto; NextPDF lo ejecuta con el presupuesto de errores fijado en cero.