PDF文档的自动化测试

发表于:2019-12-24 15:56

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:杨阳 吕元旭    来源:51Testing软件测试网原创

  1、背景
  小编所在的项目一直以来存在一个效率较低的问题:按照产品流程,我们会在某一环节为用户提供合同,并结合用户的个人信息对合同进行填充,生成pdf,进行签章后提供给用户。
  针对这个合同的测试,我们不仅需要结合用户个人信息,比对合同填充的正确性,同时也要保证用户每次生成合同的内容是正确且一致的。而针对合同的测试手段,最早开始是通过人工比对合同填充内容与数据库数据的方式进行的。但随着项目的发展,用户协议/合同数量增多、第三方接入新合同引入、代码优化重构合同相关用例必须要在多产品线进行回归,导致小编所在团队的工作量陡增。
  虽然从流程上,在新合同引入时我们可以将合同确认的工作交给上游产品或商务同学,但人为地比对仍无法保证内容的正确性,且工作内容上也带来了较多重复。
  2、自动化框架的搭建思路
  2.1、需求分析
  找到了问题,现在我们简单分析一下需求:
  场景一:第三方接入拿到新合同模板,测试合同内容填充数据正确性(填充数据与数据库数据一致性)
  场景二:合同/签章部分代码改动,原有多产品线的合同/签章需要回归测试,验证与基线代码下的合同内容一致
  2.2、设计思路:
  场景一:最直接的方案是引入外部jar包,如PDFBox( https://pdfbox.apache.org/index.html)。PDFBox是Apache下的一个开源项目,我们可以通过 PDFBox读取、创建PDF文档,加密/解密PDF文档,从PDF和XFDF格式中导入或导出表单数据 等,实现代码如下:
   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的互相转化方法如下:
   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去爬取网页源码进行解析,很方便,实现如下:
   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,执行命令即可。
  java -jar ImageTester.jar -k $APPLITOOLS_API_KEY -f <PATH>/pdf_directory/
  那么问题来了,如何把此步骤加到整个自动化的流程中呢?
  步骤一:移动下载的PDF至指定的目录
    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方法
   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;
  }
  步骤三::用断言进行比对测试
 Assert.assertTrue("Error validating PDF", validatePDF(destination));
  完事收工。
  3、总结
  以上就是小编解决此项目中问题的全部心路历程与思路。总结来说,在测试中做自动化的核心意义
  在于解决重复的、低生产力的人工工作,让机器赋能工程师们追求更快更全面与更深入的测试。

      本文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号