1. 序章

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

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

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

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

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

PDFUnitの現在のバージョン(2016.05)は、MavenCentralリポジトリーでは使用できません。 したがって、jarを手動でダウンロードしてインストールする必要があります。 手動インストールについては、公式サイトの指示に従ってください。

3. ページ数

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

@Test
public void givenSinglePage_whenCheckForOnePage_thenSuccess() {
 
    String filename = getFilePath("sample.pdf");
    AssertThat.document(filename)
      .hasNumberOfPages(1);
}

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

すべての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. パスワードで保護されたファイル

パスワードで保護されたファイルの処理も非常に簡単です。 唯一の違いは、 AssertThat.document()の呼び出しにあり、ファイルのパスワードである2番目の引数を渡す必要があります。

@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つのファイル間で完全なテキストを比較するのではなく、特定のページに特定のテキストが存在することを検証する場合は、 contains()メソッドが便利です。

@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. =150
  4. 高さ=50

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

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

@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は、画像のコンテンツをバイトごとに比較するのに十分強力です。これは、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 とは別に、 BufferedImage File InputStream 、または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で実行できることは他にもたくさんあります。 詳細については、ドキュメントページにアクセスしてください。