1. 简介
本文将介绍用于测试 PDF 文件的 PDFUnit 库。通过 PDFUnit 提供的强大 API,我们可以操作 PDF 文件并验证文本、图像、书签等多种内容。
使用 PDFUnit 可以编写相当复杂的测试用例,但本文将从最常见的应用场景入手,这些场景适用于大多数生产环境中的 PDF 文件,并为后续开发提供坚实基础。
⚠️ 重要提示:PDFUnit 仅免费用于评估目的,商业用途需授权。
2. 安装与配置
当前版本的 PDFUnit(2016.05)未在 Maven 中央仓库提供。因此需要手动下载并安装 JAR 包。请参考官方站点说明完成手动安装。
3. 页数验证
先从一个简单示例开始:验证指定 PDF 文件的页数:
@Test
public void givenSinglePage_whenCheckForOnePage_thenSuccess() {
String filename = getFilePath("sample.pdf");
AssertThat.document(filename)
.hasNumberOfPages(1);
}
getFilePath()
是与 PDFUnit 无关的辅助方法,仅返回 PDF 文件路径字符串。
所有 PDFUnit 测试都从 AssertThat.document()
调用开始,该方法准备待测文档。hasNumberOfPages()
接收一个 int
参数,指定 PDF 必须包含的页数。本例中 sample.pdf
仅包含一页,测试通过。
若实际页数与参数不符,将抛出异常。以下示例演示异常场景测试:
@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()
时需传入文件密码作为第二个参数:
@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()
方法负责比较两文件的文本内容。
若无需比较完整文本,只需验证特定页面是否存在某文本,可使用 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
,测试即通过。其他文本的存在与否不影响结果。
进一步限制验证范围:检查特定页面区域是否包含指定文本。需先理解 PageRegion
概念:
PageRegion
是页面内的矩形子区域,必须完全位于页面内。若超出页面边界将报错。其定义包含四个要素:
leftX
– 区域左边界距页面左边缘的毫米数upperY
– 区域上边界距页面顶部的毫米数width
– 区域宽度(毫米)height
– 区域高度(毫米)
通过以下属性创建 PageRegion
示例:
leftX
= 20upperY
= 10width
= 150height
= 50
理解概念后,测试用例就简单了:
@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 包含文本为 "Chapter 2" 的书签,并检查是否存在指向第 3 页的书签。
7. 图像验证
图像是 PDF 文档的重要部分。单元测试 PDF 内嵌图像同样简单:
@Test
public void whenHas2DifferentImages_thenSuccess() {
String filename = getFilePath("with_images.pdf");
AssertThat.document(filename)
.hasNumberOfDifferentImages(2);
}
此测试验证 PDF 内恰好使用两张不同图像。不同图像数量指 PDF 文档实际存储的图像数量。
但可能出现这种情况:文档内存储单个 logo 图像,却在每页重复显示。此时可见图像数量可能多于不同图像数量。验证可见图像数量:
@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
的使用:我们不限制图像出现在特定页面,而是检查整个文档的任意页面。
比较图像可接受多种形式:BufferedImage
、File
、InputStream
、URL
或文件名字符串。
8. 嵌入文件验证
某些 PDF 文档包含嵌入文件或附件,同样需要测试:
@Test
public void whenHasEmbeddedFile_thenSuccess() {
String filename = getFilePath("with_attachments.pdf");
AssertThat.document(filename)
.hasEmbeddedFile();
}
此代码验证文档至少包含一个嵌入文件。
也可验证嵌入文件名称:
@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 功能远不止于此,建议访问官方文档探索更多高级用法。