Der häufigste Testfall für PDF-Dokumente ist vermutlich, die Existenz erwarteter Texte zu überprüfen. Dafür stehen vielfältige Methoden zur Verfügung:
// Testing page content: .hasText() // pages has to be specified before // Validating expected text: .hasText().containing(..) .hasText().containing(.., WhitespaceProcessing) .hasText().endingWith(..) .hasText().endingWith(.., WhitespaceProcessing) .hasText().equalsTo(..) .hasText().equalsTo(.., WhitespaceProcessing) .hasText().matchingRegex(..) .hasText().startingWith(..) // Prove the absence of defined text: .hasText().notContaining(..) .hasText().notContaining(.., WhitespaceProcessing) .hasText().notEndingWith(..) .hasText().notMatchingRegex(..) .hasText().notStartingWith(..) // Validate multiple text in an expected order: .hasText().inOrder(..) .hasText().containingFirst(..).then(..) // Comparing visible text with ZUGFeRD data: .hasText.containingZugferdData(..)
Das Kapitel 13.5: „Behandlung von Whitespaces“ beschreibt die unterschiedlichen Möglichkeiten, mit Whitespaces umzugehen. |
|
Das Kapitel 3.39: „ZUGFeRD“ beschreibt, wie der sichtbare Inhalt von PDF-Dokumenten mit den Inhalten der unsichtbaren ZUGFeRD-Daten verglichen werden kann. |
Wenn Sie einen bestimmten Text auf der ersten Seite eines Anschreibens suchen, sieht ein Test folgendermaßen aus:
@Test public void hasText_OnFirstPage() throws Exception { String filename = "documentUnderTest.pdf"; AssertThat.document(filename) .restrictedTo(FIRST_PAGE) .hasText() .containing("Content on first page.") ; }
Ein Text auf der letzten Seite wird folgendermaßen überprüft:
@Test public void hasText_OnLastPage() throws Exception { String filename = "documentUnderTest.pdf"; AssertThat.document(filename) .restrictedTo(LAST_PAGE) .hasText() .containing("Content on last page.") ; }
Auch Tests mit beliebigen individuellen Seiten sind möglich:
@Test public void hasText_OnIndividualPages() throws Exception { String filename = "documentUnderTest.pdf"; PagesToUse pages23 = PagesToUse.getPages(2, 3); AssertThat.document(filename) .restrictedTo(pages23) .hasText() .containing("Content on") ; }
Mit der Methode |
Für typische Seiten stehen Konstanten zur Verfügung,
u.a. FIRST_PAGE, LAST_PAGE, EVEN_PAGES
und ODD_PAGES
.
Das Kapitel 13.2: „Seitenauswahl“
beschreibt die Seitenauswahl ausführlich.
Für Prüfungen, die sich auf alle Seiten beziehen, stehen drei weitere
Konstanten zur Verfügung:
ANY_PAGE
, EACH_PAGE
und
EVERY_PAGE
. Die letzten beiden sind funktional identisch
und existieren nur aus sprachlichen Gründen doppelt.
@Test public void hasText_OnEveryPage() throws Exception { String filename = "documentUnderTest.pdf"; AssertThat.document(filename) .retricted(EVERY_PAGE) .hasText() .startingWith("PDFUnit") ; }
@Test public void hasText_OnAnyPage() throws Exception { String filename = "documentUnderTest.pdf"; AssertThat.document(filename) .restrictedTo(ANY_PAGE) .hasText() .containing("Page # 3") ; }
Die Konstanten EVERY_PAGE
und EACH_PAGE
fordern, dass der zu suchende Text wirklich auf jeder
Seite existiert. Mit der Konstanten
ANY_PAGE
reicht es, wenn der erwartete Text auf
irgendeiner Seite des Dokumentes vorkommt.
Text kann aber nicht nur auf vollständigen Seite gesucht werden, sondern auch in Seitenausschnitten. Das Kapitel 3.30: „Texte - in Seitenausschnitten“ beschreibt diesen Aspekt ausführlich.
Es kann den Wunsch geben, Texte auf jeder Seite zu überprüfen, aber nicht auf der ersten Seite. Ein solcher Test sieht folgendermaßen aus:
@Test public void hasText_OnAllPagesAfter3() throws Exception { String filename = "documentUnderTest.pdf"; PagesToUse pagesAfter3 = ON_EVERY_PAGE.after(3); AssertThat.document(filename) .restrictedTo(pagesAfter3) .hasText() .containing("Content") ; }
Die Zählung der Seitenzahlen beginnt mit „1“.
Ungültige Seitenobergrenzen sind nicht unbedingt ein Fehler. Im folgenden Beispiel wird Text auf irgendeiner Seite zwischen 1 und 99 gesucht. Obwohl das Dokument nur 4 Seiten hat, endet der Test erfolgreich, weil die gesuchte Zeichenkette auf Seite 1 gefunden wird:
/** * Attention: The document has the search token on page 1. * And '1' is before '99'. So, this test ends successfully. */ @Test public void hasText_OnAnyPageBefore_WrongUpperLimit() throws Exception { String filename = "documentUnderTest.pdf"; AssertThat.document(filename) .restrictedTo(AnyPage.before(99)) .hasText() .containing("Content on") ; }
Im folgenden Beispiel wird ein Text gesucht, der sich über 2 Seiten erstreckt. Diese 2 Seiten müssen nicht volle Seiten sein, sondern können - wie im Beispiel - auch Seitenausschnitte sein. Auf dieses Weise kann Fließtext ohne Header und Footer analysiert werden:
@Test public void hasText_SpanningOver2Pages() throws Exception { String filename = "documentUnderTest.pdf"; String textOnPage1 = "Text starts on page 1 and "; String textOnPage2 = "continues on page 2"; String expectedText = textOnPage1 + textOnPage2; PagesToUse pages1to2 = PagesToUse.spanningFrom(1).to(2); // Define the section without header and footer: int leftX = 18; int upperY = 30; int width = 182; int height = 238; PageRegion regionWithoutHeaderAndFooter = new PageRegion(leftX, upperY, width, height); AssertThat.document(filename) .restrictedTo(pages1to2) .restrictedTo(regionWithoutHeaderAndFooter) .hasText() .containing(expectedText) ; }
Nach der Methode .hasText()
stehen alle oben genannte Vergleichsmethoden
zur Verfügung.
Auch die Abwesenheit von Text kann ein wichtiges Testziel sein, vor allem wenn es auf Teile einer Seite beschränkt wird. Die Tests dazu entsprechen der allgemeinen Umgangssprache:
@Test public void hasText_NotMatchingRegex() throws Exception { String filename = "documentUnderTest.pdf"; PagesToUse page2 = PagesToUse.getPage(2); PageRegion region = new PageRegion(70, 80, 90, 60); AssertThat.document(filename) .restrictedTo(page2) .restrictedTo(region) .hasNoText() ; }
Zeilenumbrüche im Text werden beim Vergleich normalisiert, sowohl Zeilenumbrüche im Text der PDF-Seite, als auch die im Suchstring. Im folgenden Beispiel stammt der zu suchende Text aus dem Dokument „Digital Signatures for PDF Documents“ von Bruno Lowagie (iText Software). Der erste Absatz sieht optisch so aus:
Tests auf den markierten Text ohne Berücksichtigung auf Zeilenumbrüche sehen folgendermaßen aus. Beide laufen erfolgreich durch, weil Whitespaces normalisiert werden.
/** * The expected search string does not contain a line break. */ @Test public void hasText_LineBreakInPDF() throws Exception { String filename = "digitalsignatures20121017.pdf"; String text = "The technology was conceived"; AssertThat.document(filename) .restrictedTo(FIRST_PAGE) .hasText() .containing(text) ; }
/** * The expected search string intentionally contains other line breaks. */ @Test public void hasText_LineBreakInExpectedString() throws Exception { String filename = "digitalsignatures20121017.pdf"; String text = "The " + "\n " + "technology " + "\n " + "was " + "\n " + "conceived"; AssertThat.document(filename) .restrictedTo(FIRST_PAGE) .hasText() .containing(text) ; }
Sollte eine Normalisierung der Whitespaces nicht erwünscht sein, so kann bei den meisten Textvergleichsmethoden noch ein zweiter Parameter übergeben werden, der die Art der Whitespace-Behandlung steuert. Folgende Möglichkeiten gibt es:
// Constants to define whitespace processing:
WhitespaceProcessing.IGNORE
WhitespaceProcessing.NORMALIZE
WhitespaceProcessing.KEEP
Sie können auch überprüfen, dass Ihr PDF-Dokument keine leere Seiten enthält:
@Test public void hasText_AnyPageEmpty() throws Exception { String filename = "documentUnderTest.pdf"; AssertThat.document(filename) .hasText() ; }
Wenn auf einer Seite mehrere Texte gesucht werden, ist es lästig, für
jeden Suchbegriff einen eigenen Funktionsaufruf zu schreiben. Deshalb
können die Funktionen containing(..)
und
notContaining(..)
mit mehreren Suchbegriffen
aufgerufen werden:
@Test public void hasText_Containing_MultipleTokens() throws Exception { String filename = "documentUnderTest.pdf"; AssertThat.document(filename) .restrictedTo(ODD_PAGES) .hasText() .containing("on", "page", "odd pagenumber") // multiple search tokens ; }
@Test public void hasText_NotContaining_MultipleTokens() throws Exception { String filename = "documentUnderTest.pdf"; AssertThat.document(filename) .restrictedTo(FIRST_PAGE) .hasText() .notContaining("even pagenumber", "Page #2") ; }
Die Tests sind erfolgreich, wenn im ersten Beispiel alle Suchbegriffe gefunden werden, oder im zweiten Beispiel eben alle nicht.
Textvergleiche können verkettet werden, sie beziehen sich dann jeweils auf die zuvor spezifizierten Seiten:
@Test public void hasText_MultipleInvocation() throws Exception { String filename = "documentUnderTest.pdf"; AssertThat.document(filename) .restrictedTo(ANY_PAGE) .hasText() .startingWith("PDFUnit") .containing("Content on last page.") .matchingRegex(".*[Cc]ontent.*") .endingWith("of 4") ; }
Die sichtbare Reihenfolge des Textes einer PDF-Seite entspricht nicht zwingend der Textreihenfolge innerhalb des PDF-Dokumentes. Im folgenden Screenshot ist der umrahmte Text ein eigenes Textobjekt, das nicht zum 'normalen' Fließtext der Seite gehört. Deshalb funktioniert auch der nachfolgende Test.
@Test public void hasText_TextNotInVisibleOrder() throws Exception { String filename = "documentUnderTest.pdf"; String firstAndLastLine = "Content at the beginning. Content at the end."; AssertThat.document(filename) .restrictedTo(FIRST_PAGE) .hasText() .containing(firstAndLastLine) ; }
Wenn Sie sich den Rahmen wegdenken, könnte der Eindruck entstehen, dass der Text „im Rahmen“ Teil des Fließtextes wäre. Ein Test mit einem Erwartungswert, der diesem vermeintlichen Fließtext entspricht, würde fehlschlagen.