扩展 Rational Functional Tester 以测试 PDF 文件
免费下载:IBM® Rational® Functional Tester 试用版 | IBM® Rational® 测试人员资源工具包 |
---|
获取免费的 Rational 软件工具包系列,下载更多的 Rational 软件试用版。 |
开始
在这一部分中,您将会学到怎样使用 IBM® Rational® Functional Tester 来创建一个通用的确认点(verification point,VP),它会比较两个 PDF 文件的文本。代码清单 1 显示了怎样将 PDF 文件放到 pdfFiles
的文件夹中。Expected.pdf
文件就是您预期的结果,而 Actual.pdf
就是获得的文件。脚本会将 Expected.pdf
和 Actual.pdf 进行比较。
首先,创建一个名为 PDFBox
的包。您可以调用 PDFBox
方法来从 Rational Functional Tester 脚本处访问 PDF 文件的文本,以载入 PDF 文件并从文件中获取数据。
代码清单 1 显示了如何使用 PDF VP 来比较两个 PDF 文件的脚本。
清单 1. 比较 PDF 文件的脚本
package testScripts; import resources.testScripts.pdfboxExampleHelper; public class pdfboxExample extends pdfboxExampleHelper { public void testMain(Object[] args) { String expected = "pdfFiles\\Expected PDF.pdf"; String actual = "pdfFiles\\Actual PDF.pdf"; vpPdfText("PDF",expected,actual).performTest(); vpPdfText("PDF Date Mask",expected,actual, MASK_DATE, MASK_DATE_NAME).performTest(); } }
第一个确认点是一个直接的比较。第二个确认点使用一个蒙版来忽略时间。
配置 Rational Functional Tester Java 项目来使用 PDFBox
为了在新的 Rational Functional Tester Java™ 项目中创建 PDFBox
,您要向 Rational Functional Tester Java 项目中 Java 构建路径的 PDFBox
JAR(Java Archive)文件添加一个引用(PDFBox-0.7.3.jar
与 FontBox-0.1.0-dev.jar
)。您可以从 Apache Software Foundation 中下载它们。对于该网站的连接,您可以在本文的结尾查看 参考资料 部分。
配置 Rational Functional Tester Java 项目以使用 google-diff-match-patch 库
Google 包 google-diff-match-patch 库作为源代码,您可以从 Diff,Match 和 Patch 库处下载它们。如果您想要得到该网站的链接,那么您可以查看本文结尾处的 参考资料 部分。为了使用它,您需要将源代码导入到 Rational Functional Tester Java 项目,或者创建一个 JAR 文件并引用 JAR 文件。这个过程中,提供了一个名为 google-diff-match-patch.jar
的 JAR 文件,该文件位于您所导入的转移文件之中。它位于名为 jars
的文件夹中。您可以通过将其添加至项目的 Java 构建路径来使用它。按照下面的方法来进行操作。
理解代码
方案由以下的部分组成:
PDFTextVerificationPoint:
它代表了 PDF 文件文本的确认。除了使用PDFBox
类来从 PDF 文件导出文本,该类还实现了IFtVerificationPoint
界面。IFtVerificationPoint
:它提供了诸如performTest
和compare
之类的方法,它使用Diff Match Patch
类来智能地比较预期 PDF 文件和实际 PDF 文件的内容。考虑到两个 PDF 文件之间可能存在一些文本上的差异,例如日期,您可以提供一个蒙版来忽略。您要使用正则表达式来实现该蒙版。performTest
和compare
方法会忽略匹配正则表达式的文本。PdfBoxHelperSuperClass:
该 Helper 超类拥有的方法和变量,可以使在文本脚本中创建 PDF 文本确认点变得容易。
图 1 显示了一个范例的 PDFBox 类图。
图 1.PDFBoxExample 类图

这一章节的剩余部分描述了 PDF 确认点是如何发挥作用的。PdfTextVerificationPoint
类会首先得到评审,然后就是 PdfBoxHelperSuperClass
。
导入声明
您需要导入 PdfTextVerificationPoint
类中的一些库,来轻松从 PDFBox、google-diff-match-patch 库、IftVerificationPoint
,以及一些设施类轻松访问方法,如代码清单 2 所示。
清单 2. 输入声明
import java.util.Calendar; import java.util.LinkedList; import name.fraser.neil.plaintext.diff_match_patch; import name.fraser.neil.plaintext.diff_match_patch.Diff; import org.pdfbox.pdmodel.PDDocument; import org.pdfbox.util.PDFTextStripper; import com.rational.test.ft.script.RationalTestScript; import com.rational.test.ft.vp.IFtVerificationPoint;
数据成员与构造器
PdfTextVerificationPoint
类会追踪大量的数据项。它拥有一个确认点,预期的文本,以及实际的数据。它还需要追踪预期 PDF 文件及实际 PDF 文件的位置。最终,PdfTextVerificationPoint
就拥有一个蒙版和一个蒙版名了。
一个蒙版就是个正则表达式,它代表了一次比较期间应该被忽略的文本。蒙版名使用蒙版所匹配的文本。PdfTextVerificationPoint
类拥有两个构造器,如代码清单 3 所示。一个构造器会传递蒙版和蒙版名,其他的则不会。两个构造器都会使用传递的参数来升级成员,然后调用一个称为 extractText
的方法,来从预期的 PDF 文件和实际的 PDF 文件处获得文本。
清单 3. 数据成员与构造器
private String vpName; private String expectedFilename; private String actualFilename; private String expectedText; private String actualText; private String mask; private String maskName; public PdfTextVerificationPoint(String vpName, String expectedFilename, String actualFilename) { super(); this.vpName = vpName; this.expectedFilename = expectedFilename; this.actualFilename = actualFilename; this.mask = ""; this.maskName = ""; this.expectedText = ""; this.actualText = ""; //Get the text from the pdf files. extractText(); } public PdfTextVerificationPoint(String vpName, String expectedFilename, String actualFilename, String mask, String maskName) { super(); this.vpName = vpName; this.expectedFilename = expectedFilename; this.actualFilename = actualFilename; this.mask = mask; this.maskName = maskName; this.expectedText = ""; this.actualText = ""; //Get the text from the pdf files. extractText(); }
从 PDF 中获取文本
PdfTextVerificationPoint
类需要从预期的和实际的 PDF 文件中获取文本。您可以使用来自 PDFBox 库的类来轻松编写代码。PDDocument
类代表了 PDF 文件,而 PDFTextStripper
知道怎样从 PDF 文件中获取文本。在您获取文本之后,您就使用蒙版名来替换匹配蒙版文本的所有实例(如果需要蒙版的话),如代码清单 4 所示。
清单 4. 获取文本
/* * Description: Extracts the text from the expected and actual pdf * files. If a mask is defined, all occurrences of the substring * the mask defines are replaced with the text maskName. */ private void extractText() { try { //Load the PDF files PDDocument expectedDoc = PDDocument.load(expectedFilename); PDDocument actualDoc = PDDocument.load(actualFilename); //Extract the text from the PDF file. PDFTextStripper stripper = new PDFTextStripper(); expectedText = stripper.getText(expectedDoc); actualText = stripper.getText(actualDoc); //Use the mask, if it is defined. Replace all substrings, //which match the regular expression, mask with maskName if(mask != "") { expectedText = expectedText.replaceAll(mask, maskName); actualText = actualText.replaceAll(mask, maskName); } //Close the PDF files. expectedDoc.close(); actualDoc.close(); } catch (Exception e) { RationalTestScript.logException(e); RationalTestScript.stop(); } }
执行测试
PdfTextVerification
点现在拥有了测试预期 PDF 文件和实际 PDF 文件所需要的一切条件。将大量的各种复杂程度的文本进行比较,并不是一项简单的任务。幸运的是,google-diff-match-patch 库可以为您完成这项工作。只要有一小部分的代码,如代码和 5 所示,您就能够获取一个列表,该列表代表了两块文本之间的差异。而且,google-diff-match-patch 库可以以一种“完美的” HTML 格式来输出结果,以图形化的方式来显示差异。
清单 5. 执行测试
public boolean performTest(boolean compareTrueEqualsPass) { /* * Get a linked list representing the difference between * the text. Each node represents text which is the * same (EQUAL), text which was added to the actual text * (INSERT), or text which was deleted from expected text * (DELETE). */ diff_match_patch dmp = new diff_match_patch(); LinkedList<Diff> diffList = dmp.diff_main(expectedText,actualText,true); dmp.diff_cleanupSemantic(diffList); //Perform the test and log the results. if(expectedText.equals(actualText) == compareTrueEqualsPass) { RationalTestScript.logTestResult( "Verification point [" + vpName + "] passed.", true, dmp.diff_prettyHtml(diffList)); return true; } else { RationalTestScript.logTestResult( "Verification point [" + vpName + "] failed.", false, dmp.diff_prettyHtml(diffList)); return false; } }
考虑一下账户变量 PDF 生成时间
让测试下的程序花不同的时间来生成 PDF 文件,成为可能的了。IftVerificationPoint
界面包含了 performTest
和 compare
方法的实例,这一点将会被考虑。调用者会提供最大测试时间(按秒计算)以及重复尝试的延迟(也以秒计算)。然后这项方法会在延迟定义的间隔时间内进行重复,直到时间用完,或者已经过了确认点为止,如代码清单 6 所示。
清单 6. 比较和执行测试
public boolean compare(double delayBetweenRetries, double maximumTestTime) { //Get the end time for the test. long endTime = (long) (Calendar.getInstance().getTimeInMillis() + (maximumTestTime * 1000)); //perform the test until time runs out or the test passes. boolean result = compare(); long nextTime = (long) (Calendar.getInstance().getTimeInMillis() + (delayBetweenRetries * 1000)); while((nextTime < endTime) && result == false) { RationalTestScript.sleep(delayBetweenRetries); extractText(); result = compare(); nextTime = (long) (Calendar.getInstance().getTimeInMillis() + (delayBetweenRetries * 1000)); } return result; } public boolean performTest(double delayBetweenRetries, double maximumTestTime, boolean compareTrueEqualsPass) { //Get the end time for the test. long endTime = (long) (Calendar.getInstance().getTimeInMillis() + (maximumTestTime * 1000)); //perform the test until time runs out or the test passes. boolean result = (compare() == compareTrueEqualsPass); long nextTime = (long) (Calendar.getInstance().getTimeInMillis() + (delayBetweenRetries * 1000)); while((nextTime < endTime) && result == false) { RationalTestScript.sleep(delayBetweenRetries); extractText(); result = (compare() == compareTrueEqualsPass); nextTime = (long) (Calendar.getInstance().getTimeInMillis() + (delayBetweenRetries * 1000)); } return performTest(compareTrueEqualsPass); }
完成剩余的方法
还有一些 get
方法,一些 performTest
方法的实例,以及一些 compare
方法的实例,如代码清单 7 所示。
清单 7. 琐碎的方法
public boolean compare() { return expectedText.equals(actualText); } public boolean compareAndLog() { return compareAndLog(true); } public boolean compareAndLog(boolean compareTrueEqualsPass) { if(expectedText.equals(actualText) == compareTrueEqualsPass) { RationalTestScript.logTestResult( "Verification point [" + vpName + "] passed.", true); return true; } else { RationalTestScript.logTestResult( "Verification point [" + vpName + "] failed.", false); return false; } } public Object getActualData() { return actualText; } public Object getBaselineData() { return null; } public Object getExpectedData() { return expectedText; } public String getVPName() { return vpName; } public boolean performTest() { return performTest(true); } public boolean performTest(double delayBetweenRetries, double maximumTestTime) { return performTest(delayBetweenRetries,maximumTestTime, true); }
Helper 超类
本方案拥有一个称作 PDFBoxHelperSuperClass
的 helper 的超类,它包含了日期字段的一个预定义蒙版,以及返回 PDF 文本确认点的一些 helper 功能,如代码清单 8 所示。
清单 8. PDFBoxHelper 超类
package util; import com.rational.test.ft.script.RationalTestScript; import com.rational.test.ft.vp.IFtVerificationPoint; /** * Description : This Super class contains methods which may * be used to compare pdf files. * * @since November 26, 2008 */ public abstract class PdfBoxHelperSuperClass extends RationalTestScript { /* * This regular expression matches a date time stamp in * the format mm/dd/yyyy hh:mm PM (or AM). It may be used * to mask the date from the expected and actual text of a * pdfTextVp. * */ public static final String MASK_DATE = "[0-9]{2}/[0-9]{2}/[0-9]{4}"; public static final String MASK_DATE_NAME = "***MM/DD/YYYY***"; /* * Description: This method returns a verification point * for the text of a pdf file. It replaces any text in the * expected and actual files, which match the regular * expression defined in the mask parameter with maskName. * One can use the mask to remove text from the vp, which * would cause the vp to fail incorrectly. A date would be * a good example of text which could be masked. * */ protected IFtVerificationPoint vpPdfText(String vpName, String expected, String actual, String mask, String maskName) { return new PdfTextVerificationPoint(vpName, expected,actual,mask, maskName); } /* * Description: This method returns a verification point * for the text of a pdf file. */ protected IFtVerificationPoint vpPdfText(String vpName, String expected, String actual) { return new PdfTextVerificationPoint(vpName,expected,actual); } }
您学到了什么
从这篇文章中,您学到了通过扩展 Rational Functional Tester 的功能,来创建 PDF 确认点。您现在应该知道怎样将 Rational Functional Tester 与开放源码包集成起来,该包可以访问 PDF 文件之中的信息。这可以帮助您创建确认点以测试 PDF 文件。您可以从 PDF 文件中抽取测试,执行确认,并考察不同的 PDF 文件的生成时间。
相关主题
- 查看 Rational Functional Tester 信息中心,在那里,您也可以查看一段短的 Rational Functional Tester 演示视频。
- 查看 Rational Functional Tester Plus,它是一个软件应用程序测试包。
- 参与 developerWorks 上 的 Rational Functional Tester 学习路线图,介绍更深入的信息。
- 通过“Software Test Engineering with IBM Rational Functional Tester”一书学习了解有关 Rational Functional Tester 的内容。
- 在 IBM Rational 软件交付平台 中了解其它应用程序,包括适用于并行开发和地域分布式团队的协作工具,以及用于架构管理、资产管理、变更和发布管理,集成需求管理、过程和组合管理,和质量管理。您可以在 IBM Rational 在线文档中心 查找产品手册、安装指南以及其它文档。
- 访问 developerWorks 上的 Rational 专区,了解有关 Rational 软件交付平台产品的技术资源和最佳实践。
- 查找 Rational 基于计算机、基于 Web,以及在线指导课程。训练您的技能,并学习更多有关 Rational 工具的课程,包括入门级和高级课程。在此目录上的课程可进行购买,包括基于计算机的和基于 Web 的培训。此外,一些“入门”课程是免费的。
- Apache Software Foundation。
- Diff、Match 和 Patch Plain Text 库。
- 下载 Rational Functional Tester 试用版。试用版是免费的,但是需要注册。
- 下载其他 IBM Rational 软件的试用版。
- 通过最适合您的方式评估 IBM 软件:下载进行试用,可以在线进行,在云环境中使用,或者在 SOA Sandbox 中花一些时间了解如何有效实施面向服务架构。