前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >PDF文档的自动化测试

PDF文档的自动化测试

作者头像
用户5521279
修改2019-11-25 18:10:04
1.7K0
修改2019-11-25 18:10:04
举报
文章被收录于专栏:搜狗测试搜狗测试

1、背景

小编所在的项目一直以来存在一个效率较低的问题:按照产品流程,我们会在某一环节为用户提供合同,并结合用户的个人信息对合同进行填充,生成pdf,进行签章后提供给用户。 针对这个合同的测试,我们不仅需要结合用户个人信息,比对合同填充的正确性,同时也要保证用户每次生成合同的内容是正确且一致的。而针对合同的测试手段,最早开始是通过人工比对合同填充内容与数据库数据的方式进行的。但随着项目的发展,用户协议/合同数量增多、第三方接入新合同引入、代码优化重构合同相关用例必须要在多产品线进行回归,导致小编所在团队的工作量陡增。 虽然从流程上,在新合同引入时我们可以将合同确认的工作交给上游产品或商务同学,但人为地比对仍无法保证内容的正确性,且工作内容上也带来了较多重复。

2、自动化框架的搭建思路

2.1、需求分析: 找到了问题,现在我们简单分析一下需求:

  • 场景一:第三方接入拿到新合同模板,测试合同内容填充数据正确性(填充数据与数据库数据一致性)
  • 场景二:合同/签章部分代码改动,原有多产品线的合同/签章需要回归测试,验证与基线代码下的合同内容一致

2.2、设计思路: 场景一:最直接的方案是引入外部jar包,如PDFBox( https://pdfbox.apache.org/index.html)。PDFBox是Apache下的一个开源项目,我们可以通过 PDFBox读取、创建PDF文档,加密/解密PDF文档,从PDF和XFDF格式中导入或导出表单数据 等,实现代码如下:

代码语言:javascript
复制
private static String readPDF(File pdf) throws InvalidPasswordException,    IOException {       try (PDDocument document = PDDocument.load(pdf)) {           document.getClass();           if (!document.isEncrypted()) {
               PDFTextStripperByArea stripper = new PDFTextStripperByArea();               stripper.setSortByPosition(true);               PDFTextStripper tStripper = new PDFTextStripper();               String pdfFileInText = tStripper.getText(document);               String lines[] = pdfFileInText.split("\\r?\\n");               List<String> pdfLines = new ArrayList<>();               StringBuilder sb = new StringBuilder();               for (String line : lines) {                   System.out.println(line);                   pdfLines.add(line);                   sb.append(line + "\n");               }               return sb.toString();           }       }       return null;}

问题:经测试使用,PDFBox提取出来的仅是文字流,而不是带有格式、顺序、标题的文档,经过PDFBox输出的字符串,我们仍需要全篇进行解析,处理并提取其中的关键字与填充信息,这样做很费劲而且不优雅。 另外一种实现思路是将文档转为有标记的文档,比如xml、html,这样的话在完成转化后我们就可以通过标签快速找到想要的元素并进行后续的操作。经调研,转化PDF文档的外部库很多,这里我们选择itextpdf。PDF和HTML的互相转化方法如下:

代码语言:javascript
复制
 public static String generatePDFFromHTML(String filename, String outputPa   th) throws ParserConfigurationException, IOException, DocumentException {           Document document = new Document();           PdfWriter writer = PdfWriter.getInstance(document, new FileOutput   Stream(outputPath));           document.open();           XMLWorkerHelper.getInstance().parseXHtml(writer, document, new Fi   leInputStream(filename));           document.close();           return outputPath;       }       public static String generateHTMLFromPDF(String filename, String outp   utPath) throws ParserConfigurationException, IOException {           PDDocument pdf = PDDocument.load(new File(filename));           PDFDomTree parser = new PDFDomTree();           Writer output = new PrintWriter(outputPath, "utf-8");           parser.writeText(pdf, output);           output.close();           if (pdf != null) {           pdf.close();           }           return outputPath; }

在完成了HTML的转化后,我们需要做的就是从HTML解析想要的元素了。小编以前写爬虫时最常用的Java HTML解析器就是Jsoup(http://www.open-open.com/jsoup/)。Jsoup不仅可以解析HTML文件、同时也直接通过HTTP、HTTPS去爬取网页源码进行解析,很方便,实现如下:

代码语言:javascript
复制
import org.jsoup.Jsoup;   import org.jsoup.nodes.Document;   import org.jsoup.nodes.Element;   public class JsoupTest {      public static void main(String[] args) {         String html = "<html><head><title>Sample Title</title></head>"            + "<body>"            + "<p>Sample Content</p>"            + "<div id='sampleDiv'><a href='www.google.com'>Google</a>"            + "<h3><a>Sample</a><h3>"            +"</div>"            + "<div id='imageDiv' class='header'><img name='google' src='goo   gle.png' />"            + "<img name='yahoo' src='yahoo.jpg' />"            +"</div>"            +"</body></html>";            Document document = Jsoup.parse(html);            //通过标签提取文字            Element link = document.select("a").first(); System.out.println("Text: " + link.text());            // 查找.png结尾的图片的名字            Elements pngs = document.select("img[src$=.png]"); for (Element png : pngs) {            System.out.println("Name: " + png.attr("name"));         }            // 查找H3元素之后的元素            Elements sampleLinks = document.select("h3 > a"); for (Element link : sampleLinks) {            System.out.println("Text: " + link.text());         }  } }

在前两步完成后,后面要做的就是从数据库拿数据进行比对,这里就不再赘述了

场景二:此场景的整体思路就是拿到此基线下的各合同PDF,然后拿新生成的合同进行比对,比对内容包括格式、文案、图片、签章坐标系等。如果复用上面的思路,那么实现原理是提取合同中的所有元素进行比较。这里存在的一个问题是一整个流程下来可能存在十数个合同,我们需要针对每个合同进行一一解析;另外此方法也无法针对位置一类的校验点进行检查。 经小编的再次调研,网上有很多的文档比对解决方案,其中applitools(https://applitools.com/)提供了CLI的解决方案,我们只需注册一个免费账号,获取到apikey,执行命令即可。

代码语言:javascript
复制
java -jar ImageTester.jar -k $APPLITOOLS_API_KEY -f <PATH>/pdf_directory/

那么问题来了,如何把此步骤加到整个自动化的流程中呢?

步骤一:移动下载的PDF至指定的目录

代码语言:javascript
复制
File downloadedPDF = new File("C:\\Users\\Tests\\Downloads\\" + contract+   ".pdf");   String destination = "C:\\Users\\resources\\contracts\\" + contract+ ".pd   f";   FileUtils.moveFile(downloadedPDF, destination);    public static boolean moveFile(File file, String destination){           File existingFile = new File(destination);           if(existingFile.exists()){               existingFile.delete();           }           return file.renameTo(new File(destination));       }

步骤二:执行上面的jar包,小编这里写了个各处可用的Util方法

代码语言:javascript
复制
public static boolean validatePDF(String filepath) throws IOException, In   terruptedException {           String command = String.format(                   "java -jar C:\\Users\\resources\\contracts\\ImageTester.j   ar -k %s -f %s",                   System.getProperty("applitools.api.key"),                   filepath);           Process process = Runtime.getRuntime().exec(command);           process.waitFor();           String stream = IOUtils.toString(process.getInputStream(), "UTF-   8");           System.out.println(stream);           if(stream != null && stream.contains("Mismatch")){               return false;           }           return true;}

步骤三::用断言进行比对测试

代码语言:javascript
复制
Assert.assertTrue("Error validating PDF", validatePDF(destination));

完事收工。

3、总结

以上就是小编解决此项目中问题的全部心路历程与思路。总结来说,在测试中做自动化的核心意义 在于解决重复的、低生产力的人工工作,让机器赋能工程师们追求更快更全面与更深入的测试。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-11-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 搜狗测试 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、背景
    • 2、自动化框架的搭建思路
    • 3、总结
    相关产品与服务
    数据库
    云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档