Comparez la sortie PDF en Java pour les tests d'instantanés

Avez-vous déjà voulu tester automatiquement le PDF de sortie final, y compris la mise en page, lors du développement d'une application qui produit des PDF tels que des formulaires? Dans ce document, je vais vous montrer comment effectuer des tests de régression, y compris la mise en page par imagerie et la comparaison de deux fichiers PDF.

Idée basique

Environnement de confirmation

Jusqu'à l'imagerie PDF

La création d'images PDF est plus facile que vous ne le pensez avec Apache PDFBox. Comme mentionné précédemment, le but est un test de régression automatique, donc si le nombre de pages ou la taille de la page est différent, le test échouera et abandonnera.

Plus le DPI pour l'imagerie est élevé, plus des comparaisons plus précises peuvent être effectuées à l'aide d'images haute résolution, mais cela nécessite des ressources de la machine (CPU, mémoire).

static void assertPdfEquals(InputStream expected, InputStream actual) throws IOException {
    try (PDDocument doc1 = PDDocument.load(expected);
         PDDocument doc2 = PDDocument.load(actual)) {
        //Le test a échoué si le nombre de pages est différent
        assertEquals(doc1.getNumberOfPages(), doc2.getNumberOfPages());

        PDFRenderer renderer1 = new PDFRenderer(doc1);
        PDFRenderer renderer2 = new PDFRenderer(doc2);
        for (int i = 0; i < doc1.getNumberOfPages(); i++) {
            BufferedImage image1 = renderer1.renderImageWithDPI(i, 144, ImageType.RGB);
            BufferedImage image2 = renderer2.renderImageWithDPI(i, 144, ImageType.RGB);

            //Le test échoue même si la taille est différente
            assertEquals(image1.getWidth(), image2.getWidth());
            assertEquals(image1.getHeight(), image2.getHeight());

            //Tester la correspondance de l'image et générer l'image différentielle dans un fichier temporaire si elles ne correspondent pas
            Path path = Files.createTempFile("diff-" + i + "-", ".png ");
            try (OutputStream os = Files.newOutputStream(path)) {
                assertTrue(compareImage(image1, image2, os), path);
            }
        }
    }
}

Jusqu'à comparaison d'images

La comparaison d'images n'est pas particulièrement difficile tant que vous ne vérifiez que la correspondance exacte des valeurs RVB pixel par pixel. Le but n'est pas seulement de comparer, mais de repeindre les pixels incompatibles avec une couleur de surbrillance pour créer une image différentielle.

static boolean compareImage(BufferedImage image1, BufferedImage image2, OutputStream os) throws IOException {
    boolean matched = true;
    for (int x = 0; x < image1.getWidth(); x++) {
        for (int y = 0; y < image1.getHeight(); y++) {
            int p1 = image1.getRGB(x, y);
            int p2 = image2.getRGB(x, y);
            //Laissez les pixels correspondants tels quels et changez les pixels sans correspondance en magenta
            if (p1 != p2) {
                matched = false;
                image1.setRGB(x, y, Color.MAGENTA.getRGB());
            }
        }
    }
    //Image de différence de sortie
    if (os != null) {
        ImageIO.write(image1, "png", os);
    }
    return matched;
}

Exemple de sortie d'image de différence

Contrairement au PDF attendu, dans le PDF réel, «la date de l'en-tête a été ajoutée», «l'élément 3 de l'élément a été supprimé» et «les sous-totaux et totaux ont changé en raison de la suppression de l'élément 3». Peut être lu en le comparant à l'image de différence.

Supplément

    //Les pixels correspondants sont noirs, les pixels sans correspondance sont blancs
    if (p1 == p2) {
        image1.setRGB(x, y, Color.BLACK.getRGB());
    } else {
        matched = false;
        image1.setRGB(x, y, Color.WHITE.getRGB());
    }

image.png

Résumé

J'ai présenté comment effectuer un test d'instantané en convertissant la sortie PDF en image. Il y a une limite au test de régression visuelle pour les humains lorsque l'on essaie de confirmer que "non seulement les données sont sorties mais également affichées dans la bonne mise en page" comme PDF.

Si vous utilisez la méthode introduite cette fois, vous détecterez non seulement le dégraissage de l'application que vous implémentez, mais vous remarquerez également des changements de mise en page involontaires lors de la mise à niveau de la bibliothèque de sortie PDF, afin que vous puissiez développer avec plus de tranquillité d'esprit. Il n'y en a pas.

Les références

Recommended Posts

Comparez la sortie PDF en Java pour les tests d'instantanés
Comparer des listes en Java
Les débutants jouent à des jeux Janken en Java
J'ai créé un PDF avec Java.
[Pour les débutants] Exécutez Selenium sur Java
Sortie mixte du calendrier occidental en Java
Enregistrer la sortie dans un fichier en Java
Sortie PDF et TIFF avec Java 8
Paramètres de débogage SSL dans Java
Java dessine des formes dans des documents PDF
Meilleures pratiques modernes pour les tests Java
Premiers pas pour l'apprentissage profond en Java
Points clés pour l'introduction de gRPC en Java
Date de sortie en Java au format étendu ISO 8601
Programmer les en-têtes et pieds de page PDF en Java
Lire une chaîne dans un fichier PDF avec Java
ChatWork4j pour l'utilisation de l'API ChatWork en Java
Techniques de lecture du code source Java dans Eclipse
Essayez de gratter environ 30 lignes en Java (sortie CSV)
Préparez la sortie du journal à l'aide de log4j dans Eclipse.
La solution pour NetBeans 8.2 ne fonctionne pas dans l'environnement Java 9
J'ai essayé de sortir quatre-vingt-dix-neuf en Java
Définissez un affichage contextuel pour le langage Java avec vim.
[Java] Créons un Minecraft Mod 1.14.4 [99. Mod output]
[Java] Quelque chose est affiché comme "-0.0" dans la sortie
Activer / désactiver SNI en Java pour chaque communication
Points à connaître avec Java Equals
[Java] sortie, variables
Pour l'apprentissage JAVA (2018-03-16-01)
Partition en Java
Changements dans Java 11
Janken à Java
Taux circonférentiel à Java
Java pour instruction
FizzBuzz en Java
Essayez Easy Ramdom, un outil de test PropertyBase pour Java
Remarque sur l'initialisation des champs dans le didacticiel Java
Obtention des objets Locale pour tous les paramètres régionaux disponibles en Java
Sortie true avec if (a == 1 && a == 2 && a == 3) en Java (identifiant invisible)
Ceci et cela pour éditer ini en Java. : inieditor-java
J'ai essayé d'utiliser l'instruction Extended for en Java
Exemple de code pour la sortie du journal par Java + SLF4J + Logback
[mémo] Générer une paire de clés RSA pour SSH en Java