Vergleichen Sie die PDF-Ausgabe in Java für Snapshot-Tests

Wollten Sie schon immer die endgültige Ausgabe-PDF-Datei einschließlich des Layouts automatisch testen, wenn Sie eine Anwendung entwickeln, die PDF-Dateien wie Formulare ausgibt? In diesem Dokument werde ich Ihnen zeigen, wie Sie Regressionstests einschließlich Layout durchführen, indem Sie zwei PDF-Dateien abbilden und vergleichen.

Grundidee

Bestätigungsumgebung

Bis zur PDF-Bildgebung

Das Imaging von PDFs ist mit Apache PDFBox einfacher als Sie vielleicht denken. Wie bereits erwähnt, ist der Zweck ein automatischer Regressionstest. Wenn also die Anzahl der Seiten oder die Seitengröße unterschiedlich ist, schlägt der Test fehl und gibt auf.

Je größer der DPI für die Bildgebung ist, desto präzisere Vergleiche können mit hochauflösenden Bildern durchgeführt werden. Dies erfordert jedoch Maschinenressourcen (CPU, Speicher).

static void assertPdfEquals(InputStream expected, InputStream actual) throws IOException {
    try (PDDocument doc1 = PDDocument.load(expected);
         PDDocument doc2 = PDDocument.load(actual)) {
        //Test fehlgeschlagen, wenn die Anzahl der Seiten unterschiedlich ist
        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);

            //Der Test schlägt fehl, auch wenn die Größe unterschiedlich ist
            assertEquals(image1.getWidth(), image2.getWidth());
            assertEquals(image1.getHeight(), image2.getHeight());

            //Testen Sie die Bildübereinstimmung und geben Sie das Differenzbild in eine temporäre Datei aus, wenn sie nicht übereinstimmen
            Path path = Files.createTempFile("diff-" + i + "-", ".png ");
            try (OutputStream os = Files.newOutputStream(path)) {
                assertTrue(compareImage(image1, image2, os), path);
            }
        }
    }
}

Bis zum Bildvergleich

Der Bildvergleich ist nicht besonders schwierig, solange Sie nur Pixel für Pixel die genaue Übereinstimmung der RGB-Werte überprüfen. Es geht nicht nur darum, zu vergleichen, sondern die nicht übereinstimmenden Pixel mit einer Hervorhebungsfarbe neu zu streichen, um ein differenzielles Bild zu erstellen.

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);
            //Lassen Sie die übereinstimmenden Pixel unverändert und ändern Sie die nicht übereinstimmenden Pixel in Magenta
            if (p1 != p2) {
                matched = false;
                image1.setRGB(x, y, Color.MAGENTA.getRGB());
            }
        }
    }
    //Ausgangsdifferenzbild
    if (os != null) {
        ImageIO.write(image1, "png", os);
    }
    return matched;
}

Beispiel für die Ausgabe von Differenzbildern

Im Gegensatz zum erwarteten PDF wurden im tatsächlichen PDF "das Datum der Überschrift hinzugefügt", "Punkt 3 des Artikels wurde gelöscht" und "Zwischensummen und Summen haben sich aufgrund des Löschens von Punkt 3 geändert". Kann durch Vergleich mit dem Differenzbild gelesen werden.

Ergänzung

    //Übereinstimmende Pixel sind schwarz, nicht übereinstimmende Pixel sind weiß
    if (p1 == p2) {
        image1.setRGB(x, y, Color.BLACK.getRGB());
    } else {
        matched = false;
        image1.setRGB(x, y, Color.WHITE.getRGB());
    }

image.png

Zusammenfassung

Ich stellte vor, wie ein Schnappschuss-Test durchgeführt wird, indem die PDF-Ausgabe in ein Bild konvertiert wird. Der visuelle Regressionstest für Menschen ist begrenzt, wenn versucht wird zu bestätigen, dass "nicht nur die Daten ausgegeben, sondern auch im richtigen Layout angezeigt werden" wie PDF.

Wenn Sie die diesmal eingeführte Methode verwenden, erkennen Sie nicht nur die Entfettung der von Ihnen implementierten Anwendung, sondern bemerken auch unbeabsichtigte Layoutänderungen, wenn Sie die PDF-Ausgabebibliothek aktualisieren, sodass Sie beruhigter entwickeln können. Da ist gar nichts.

Verweise

Recommended Posts

Vergleichen Sie die PDF-Ausgabe in Java für Snapshot-Tests
Listen in Java vergleichen
Anfänger spielen Janken-Spiele in Java
Ich habe ein PDF mit Java erstellt.
[Für Anfänger] Führen Sie Selenium auf Java aus
Gemischte Ausgabe des westlichen Kalenders in Java
Protokollausgabe in Datei in Java
PDF und TIFF mit Java 8 ausgeben
Einstellungen für das SSL-Debugging in Java
Java zeichnet Formen in PDF-Dokumenten
Moderne Best Practices für Java-Tests
Erste Schritte für tiefes Lernen in Java
Wichtige Punkte für die Einführung von gRPC in Java
Ausgabedatum in Java im erweiterten ISO 8601-Format
Programmieren Sie PDF-Kopf- und Fußzeilen in Java
Lesen Sie eine Zeichenfolge in einer PDF-Datei mit Java
ChatWork4j für die Verwendung der ChatWork-API in Java
Techniken zum Lesen von Java-Quellcode in Eclipse
Versuchen Sie, etwa 30 Zeilen in Java zu kratzen (CSV-Ausgabe)
Bereiten Sie die Protokollausgabe mit log4j in Eclipse vor.
Lösung für NetBeans 8.2 funktioniert nicht in Java 9-Umgebung
Ich habe versucht, neunundneunzig in Java auszugeben
Stellen Sie mit vim die Popup-Anzeige für die Java-Sprache ein.
[Java] Erstellen wir einen Minecraft Mod 1.14.4 [99. Mod-Ausgabe]
[Java] In der Ausgabe wird etwas als "-0.0" angezeigt
Aktivieren / Deaktivieren von SNI in Java für jede Kommunikation
Punkte, die bei Java beachtet werden müssen, sind gleich
[Java] Ausgabe, Variablen
Für JAVA-Lernen (2018-03-16-01)
Partisierung in Java
Änderungen in Java 11
Janken in Java
Umfangsrate in Java
Java für Anweisung
FizzBuzz in Java
Probieren Sie Easy Ramdom, ein PropertyBase-Testtool für Java
Ein Hinweis zum Initialisieren von Feldern im Java-Lernprogramm
Abrufen von Gebietsschemaobjekten für alle in Java verfügbaren Gebietsschemas
Ausgabe true mit if (a == 1 && a == 2 && a == 3) in Java (Invisible Identifier)
Dies und das zum Bearbeiten von ini in Java. : inieditor-java
Ich habe versucht, die erweiterte for-Anweisung in Java zu verwenden
Beispielcode für die Protokollausgabe von Java + SLF4J + Logback
[memo] RSA-Schlüsselpaar für SSH in Java generieren