PDFUnitへのガイド

PDFUnitのガイド

1. 前書き

この記事では、PDFをテストするためのPDFUnitライブラリについて説明します。

PDFUnitが提供する強力なAPIを使用して、PDFを操作し、テキスト、画像、ブックマーク、その他多くのことを検証できます。

最終的にはPDFUnitを使用して非常に複雑なテストケースを作成できますが、ほとんどの本番PDFに適用され、さらなる開発のための優れた基盤を提供する最も一般的なユースケースから始めましょう。

重要な注意:PDFUnitは評価目的で無料で利用できますが、商用利用はできません。

2. インストールとセットアップ

現在のバージョンのPDFUnit(2016.05)は、Maven Centralリポジトリでは利用できません。 したがって、jarを手動でダウンロードしてインストールする必要があります。 手動インストールの場合は、instructions on the official siteに従ってください。

3. ページ数

特定のPDFファイルのページ数を単純に検証する簡単な例から始めましょう。

@Test
public void givenSinglePage_whenCheckForOnePage_thenSuccess() {

    String filename = getFilePath("sample.pdf");
    AssertThat.document(filename)
      .hasNumberOfPages(1);
}

getFilePath()は、PDFUnitとは関係のない単純なメソッドであり、PDFファイルのパスをStringとして返すだけです。

すべてのPDFUnitテストは、テスト用にドキュメントを準備するAssertThat.document()の呼び出しから始まります。 hasNumberOfPages()は、PDFに含める必要のあるページ数を指定する引数としてintを取ります。 この場合、ファイルsample.pdfには1ページしか含まれていないため、テストは成功します。

実際のページ数が引数と一致しない場合、例外がスローされます。

例外がスローされたときにシナリオをテストする方法の例を見てみましょう。

@Test(expected = PDFUnitValidationException.class)
public void givenMultiplePages_whenCheckForOnePage_thenException() {
    String filename = getFilePath("multiple_pages.pdf");
    AssertThat.document(filename)
      .hasNumberOfPages(1);
}

この場合、ファイルmultiple_pages.pdfには複数のページが含まれています。 したがって、PDFUnitValidationException例外がスローされます。

4. パスワードで保護されたファイル

パスワードで保護されたファイルの処理もまた非常に簡単です。 唯一の違いは、pass a second argument which is the password of the fileを実行する必要があるAssertThat.document()の呼び出しにあります。

@Test
public void givenPwdProtected_whenOpenWithPwd_thenSuccess() {
    String filename = getFilePath("password_protected.pdf");
    String userPassword = "pass1";

    AssertThat.document(filename, userPassword)
      .hasNumberOfPages(1);
}

5. テキストの比較

次に、テストPDF(sample.pdf)と参照PDF(sample_reference.pdf)を比較してみましょう。 テスト対象のファイルのテキストが参照ファイルと同じ場合、テストは成功します。

@Test
public void whenMatchWithReferenceFile_thenSuccess() {
    String testFileName = getFilePath("sample.pdf");
    String referenceFileName = getFilePath("sample_reference.pdf");

    AssertThat.document(testFileName)
      .and(referenceFileName)
      .haveSameText();
}

haveSameText()は、2つのファイル間でテキストを比較するすべての作業を実行するメソッドです。

2つのファイル間で完全なテキストを比較するのではなく、特定のページに特定のテキストが存在することを検証する場合は、containing()メソッドが便利です。

@Test
public void whenPage2HasExpectedText_thenSuccess() {

    String filename = getFilePath("multiple_pages.pdf");
    String expectedText = "Chapter 1, content";

    AssertThat.document(filename)
      .restrictedTo(PagesToUse.getPage(2))
      .hasText()
      .containing(expectedText);
}

上記のテストは、multiple_pages.pdfファイルのページ#2にページのどこかにexpectedTextが含まれている場合に成功します。 expectedText以外の他のテキストの有無は、結果に影響しません。

ここで、特定のテキストがページ全体ではなくページの特定の領域に存在するかどうかを検証することにより、テストをより制限的にします。 このためには、PageRegionの概念を理解する必要があります。

PageRegionは、テスト対象の実際のページ内の長方形のサブセクションです。 PageRegionは、実際のページに完全に含まれている必要があります。 PageRegionのいずれかの部分が実際のページから外れると、エラーが発生します。

PageRegionは、次の4つの要素で定義されます。

  1. leftX –垂直線がページの左端の垂直エッジから離れているミリメートル数

  2. upperY –水平線がページの最上部の水平エッジから離れているミリメートル数

  3. width –領域の幅(ミリメートル単位)

  4. height –領域の高さミリメートル

この概念をよりよく理解するために、次の属性を使用してPageRegionを作成しましょう。

  1. leftX = 20

  2. upperY = 10

  3. width = 150

  4. height = 50

上記のPageRegion:のおおよその画像表現は次のとおりです。

image

概念が明確になると、対応するテストケースは比較的単純になります。

@Test
public void whenPageRegionHasExpectedtext_thenSuccess() {
    String filename = getFilePath("sample.pdf");
    int leftX = 20;
    int upperY = 10;
    int width = 150;
    int height = 50;
    PageRegion regionTitle = new PageRegion(leftX, upperY, width, height);

    AssertThat.document(filename)
      .restrictedTo(PagesToUse.getPage(1))
      .restrictedTo(regionTitle)
      .hasText()
      .containing("Adobe Acrobat PDF Files");
}

ここでは、PDFファイルのページ#1内にPageRegionを作成し、この領域のテキストを検証しました。

6. ブックマーク

ブックマークに関連するいくつかのテストケースを見てみましょう。

@Test
public void whenHasBookmarks_thenSuccess() {
    String filename = getFilePath("with_bookmarks.pdf");

    AssertThat.document(filename)
      .hasNumberOfBookmarks(5);
}

PDFファイルに正確に5つのブックマークがある場合、このテストは成功します。

ブックマークのラベルも確認できます。

@Test
public void whenHasBookmarksWithLabel_thenSuccess() {
    String filename = getFilePath("with_bookmarks.pdf");

    AssertThat.document(filename)
      .hasBookmark()
      .withLabel("Chapter 2")
      .hasBookmark()
      .withLinkToPage(3);
}

ここでは、指定されたPDFに「第2章」というテキストのブックマークがあることを確認しています。 また、ページ#3にリンクするブックマークがあるかどうかも確認します。

7. 画像

画像は、PDF文書のもう1つの重要な側面です。 PDF内の画像のユニットテストは非常に簡単です。

@Test
public void whenHas2DifferentImages_thenSuccess() {
    String filename = getFilePath("with_images.pdf");

    AssertThat.document(filename)
      .hasNumberOfDifferentImages(2);
}

このテストでは、PDF内で2つの異なる画像が使用されていることを確認します。 異なる画像の数とは、PDFドキュメント内に保存されている実際の画像の数を指します。

ただし、ドキュメント内に単一のロゴ画像が保存されていても、ドキュメントのすべてのページに表示される可能性があります。 これは、表示可能な画像の数を指し、異なる画像の数よりも多くなる場合があります。

表示されている画像を確認する方法を見てみましょう。

@Test
public void whenHas2VisibleImages_thenSuccess() {
    String filename = getFilePath("with_images.pdf");
    AssertThat.document(filename)
      .hasNumberOfVisibleImages(2);
}

PDFUnit is powerful enough to compare the content of images byte-by-byte.これは、PDF内の画像と参照画像が完全に等しくなければならないことも意味します。

バイト比較のため、BMPやPNGなどの異なる形式の画像は等しくないと見なされます。

@Test
public void whenImageIsOnAnyPage_thenSuccess() {
    String filename = getFilePath("with_images.pdf");
    String imageFile = getFilePath("Superman.png");

    AssertThat.document(filename)
      .restrictedTo(AnyPage.getPreparedInstance())
      .hasImage()
      .matching(imageFile);
}

ここでAnyPageが使用されていることに注意してください。 画像の発生を特定のページに制限するのではなく、ドキュメント全体の任意のページに制限します。

比較するイメージは、ファイル名を表すStringとは別に、BufferedImageFileInputStream、またはURLの形式をとることができます。

8. 埋め込みファイル

特定のPDFドキュメントには、ファイルまたは添付ファイルが埋め込まれています。 これらもテストする必要があります。

@Test
public void whenHasEmbeddedFile_thenSuccess() {
    String filename = getFilePath("with_attachments.pdf");

    AssertThat.document(filename)
      .hasEmbeddedFile();
}

これにより、テスト対象のドキュメントに少なくとも1つの埋め込みファイルがあるかどうかが検証されます。

埋め込みファイルの名前も確認できます。

@Test
public void whenHasmultipleEmbeddedFiles_thenSuccess() {
    String filename = getFilePath("with_attachments.pdf");

    AssertThat.document(filename)
      .hasNumberOfEmbeddedFiles(4)
      .hasEmbeddedFile()
      .withName("complaintform1.xls")
      .hasEmbeddedFile()
      .withName("complaintform2.xls")
      .hasEmbeddedFile()
      .withName("complaintform3.xls");
}

さらに一歩進んで、埋め込まれたファイルの内容を確認することもできます。

@Test
public void whenEmbeddedFileContentMatches_thenSuccess() {
    String filename = getFilePath("with_attachments.pdf");
    String embeddedFileName = getFilePath("complaintform1.xls");

    AssertThat.document(filename)
      .hasEmbeddedFile()
      .withContent(embeddedFileName);
}

このセクションのすべての例は、比較的簡単で自明です。

9. 結論

このチュートリアルでは、PDFテストに関連する最も一般的な使用例をカバーするいくつかの例を見てきました。

ただし、PDFUnitで実行できることは他にもたくさんあります。詳細については、必ずdocumentation pageにアクセスしてください。