• Airtest一:批量运行脚本、汇总报告、导出报告


     
     

    一、项目目录

    二、各文件说明

    1、air_case。需要执行的脚本air文件,例如login.air。后续直接添加该文件即可,其他的文件都不用动
     
    2、export_log。该文件夹自动生成,是自动导出的日志,发给其他人的时候,直接发送该包,日志中的路径用的相对路径。可以直接找到文件
     
    3、log。该文件夹自动生成,是运行中产生的log.txt文件
     
    4、my_runner.py。运行case的启动器,整个demo的入口文件。【一般报错的都是这个文件】已经将这个文件改成使用导出模板的方式
     
    5、report.py。生成报告入口,但是my_runner.py已经运行完case,生成了报告,无需再执行此文件
     
    6、summary_template.html。汇总报告的模版,执行完case汇总的报告是根据该文件的样式产生的。
     
    7、util.py。工具
     

    三、运行方式

    python3 my_runner.py
     

    四、 说明

    我的demo是基于图像识别的浏览器case,没有连接设备,执行手机的在my_runner.py将devices添加进去即可
     

    五、各文件源码

     

    my_runner.py文件

      1 #!/usr/bin/env python
      2 # -*- coding: utf-8 -*-
      3 # @Time    : 2020-02-23 13:33
      4 # @Author  : zhangxue
      5 # @File    : my_runner.py
      6 # @Desc    :
      7 #!/usr/bin/env python
      8 # -*- coding: utf-8 -*-
      9 from airtest.cli.runner import AirtestCase, run_script
     10 from argparse import *
     11 import airtest.report.report as report
     12 import jinja2
     13 import shutil
     14 import os
     15 import io
     16 
     17 
     18 class CustomAirtestCase(AirtestCase):
     19     # @classmethod
     20     # def setUpClass(cls):
     21     #     super(CustomAirtestCase,cls).setUpClass()
     22 
     23 
     24     def setUp(self):
     25         print("custom setup")
     26         super(CustomAirtestCase, self).setUp()
     27 
     28     def tearDown(self):
     29         print("custom tearDown")
     30         super(CustomAirtestCase, self).setUp()
     31 
     32     def run_air(self, root_dir='', device=[], scriptname='air_case'):
     33         # 用例目录
     34         script_path = root_dir + "/" + scriptname
     35         # 聚合结果
     36         results = []
     37         # 创建log文件
     38         root_log = root_dir + '/' + 'log'
     39         if os.path.isdir(root_log):
     40             shutil.rmtree(root_log)
     41         else:
     42             os.makedirs(root_log)
     43             print(str(root_log) + '  is created')
     44 
     45         # 创建export_log文件
     46         export_log = root_dir + '/' + 'export_log'
     47         if os.path.isdir(export_log):
     48             shutil.rmtree(export_log)
     49         else:
     50             os.makedirs(export_log)
     51             print(str(export_log) + '  is created')
     52 
     53         for f in os.listdir(script_path):
     54             if f.endswith(".air"):
     55                 # f为.air案例名称:login.air
     56                 airName = f
     57                 script = os.path.join(script_path, f)
     58                 # airName_path为.air的全路径/Users/zhangxue/Documents/study/airtest_fppui/air_case/login.air
     59                 print("当前运行脚本路径:" + str(script))
     60                 # 日志存放路径和名称:/Users/zhangxue/Documents/study/airtest_fppui/log/login/log.html
     61                 log = os.path.join(root_dir, 'log' + '/' + airName.replace('.air', ''))
     62                 print("log路径:" + str(log))
     63                 if os.path.isdir(log):
     64                     shutil.rmtree(log)
     65                 else:
     66                     os.makedirs(log)
     67                     print(str(log) + '  is created')
     68                 # global args
     69                 args = Namespace(device=device, log=log, recording=None, script=script, compress=1)
     70                 try:
     71                     run_script(args, AirtestCase)
     72                 except:
     73                     pass
     74                 finally:
     75                     export_output_file = os.path.join(export_log + "/" + airName.replace('.air', '.log') + '/log.html')
     76                     rpt = report.LogToHtml(script_root=script, log_root=log, export_dir=export_log)
     77                     rpt.report("log_template.html", output_file=export_output_file)
     78                     result = {}
     79                     result["name"] = airName.replace('.air', '')
     80                     result["result"] = rpt.test_result
     81                     results.append(result)
     82 
     83         # 生成聚合报告
     84         env = jinja2.Environment(
     85             loader=jinja2.FileSystemLoader(root_dir),
     86             extensions=(),
     87             autoescape=True
     88         )
     89         template = env.get_template("summary_template.html", root_dir)
     90         html = template.render({"results": results})
     91         output_file = os.path.join(export_log, "summary.html")
     92         with io.open(output_file, 'w', encoding="utf-8") as f:
     93             f.write(html)
     94         print(output_file)
     95 
     96 
     97 if __name__ == '__main__':
     98     test = CustomAirtestCase()
     99     root = os.path.abspath(".")
    100     print("root_path路径:  " + root)
    101 
    102     device = ['']
    103 
    104     test.run_air(root)
    105 
    106 my_runner.py文件
    my_runner.py文件

    report.py文件

      1 # -*- coding: utf-8 -*-
      2 
      3 import os
      4 import io
      5 import types
      6 import shutil
      7 import json
      8 import jinja2
      9 from airtest.utils.compat import decode_path
     10 import airtest.report.report as R
     11 
     12 HTML_FILE = "log.html"
     13 HTML_TPL = "log_template.html"
     14 STATIC_DIR = os.path.dirname(R.__file__)
     15 
     16 def get_parger(ap):
     17     ap.add_argument("script", help="script filepath")
     18     ap.add_argument("--outfile", help="output html filepath, default to be log.html")
     19     ap.add_argument("--static_root", help="static files root dir")
     20     ap.add_argument("--log_root", help="log & screen data root dir, logfile should be log_root/log.txt")
     21     ap.add_argument("--record", help="custom screen record file path", nargs="+")
     22     ap.add_argument("--export", help="export a portable report dir containing all resources")
     23     ap.add_argument("--lang", help="report language", default="en")
     24     ap.add_argument("--plugins", help="load reporter plugins", nargs="+")
     25     return ap
     26 
     27 
     28 def get_script_info(script_path):
     29     script_name = os.path.basename(script_path)
     30     result_json = {"name": script_name, "author": None, "title": script_name, "desc": None}
     31     return json.dumps(result_json)
     32 
     33 
     34 def _make_export_dir(self):
     35     dirpath = self.script_root
     36     logpath = self.script_root
     37     # copy static files
     38     for subdir in ["css", "fonts", "image", "js"]:
     39         dist = os.path.join(dirpath, "static", subdir)
     40         shutil.rmtree(dist, ignore_errors=True)
     41         self.copy_tree(os.path.join(STATIC_DIR, subdir), dist)
     42 
     43     return dirpath, logpath
     44 
     45 
     46 def report(self, template_name, output_file=None, record_list=None):
     47     """替换LogToHtml中的report方法"""
     48     self._load()
     49     steps = self._analyse()
     50     # 修改info获取方式
     51     info = json.loads(get_script_info(self.script_root))
     52 
     53     if self.export_dir:
     54         self.script_root, self.log_root = self._make_export_dir()
     55         output_file = os.path.join(self.script_root, HTML_FILE)
     56         self.static_root = "static/"
     57 
     58     if not record_list:
     59         record_list = [f for f in os.listdir(self.log_root) if f.endswith(".mp4")]
     60     records = [os.path.join(self.log_root, f) for f in record_list]
     61 
     62     if not self.static_root.endswith(os.path.sep):
     63         self.static_root = self.static_root.replace("\", "/")
     64         self.static_root += "/"
     65 
     66     data = {}
     67     data['steps'] = steps
     68     data['name'] = os.path.basename(self.script_root)
     69     data['scale'] = self.scale
     70     data['test_result'] = self.test_result
     71     data['run_end'] = self.run_end
     72     data['run_start'] = self.run_start
     73     data['static_root'] = self.static_root
     74     data['lang'] = self.lang
     75     data['records'] = records
     76     data['info'] = info
     77 
     78     return self._render(template_name, output_file, **data)
     79 
     80 
     81 def get_result(self):
     82     return self.test_result
     83 
     84 
     85 def main(args):
     86     # script filepath
     87     path = decode_path(args.script)
     88     record_list = args.record or []
     89     log_root = decode_path(args.log_root) or path
     90     static_root = args.static_root or STATIC_DIR
     91     static_root = decode_path(static_root)
     92     export = decode_path(args.export) if args.export else None
     93     lang = args.lang if args.lang in ['zh', 'en'] else 'zh'
     94     plugins = args.plugins
     95 
     96     # gen html report
     97     rpt = R.LogToHtml(path, log_root, static_root, export_dir=export, lang=lang, plugins=plugins)
     98     # override methods
     99     rpt._make_export_dir = types.MethodType(_make_export_dir, rpt)
    100     rpt.report = types.MethodType(report, rpt)
    101     rpt.get_result = types.MethodType(get_result, rpt)
    102 
    103     rpt.report(HTML_TPL, output_file=args.outfile, record_list=record_list)
    104 
    105     return rpt.get_result()
    106 
    107 
    108 if __name__ == "__main__":
    109     import argparse
    110     ap = argparse.ArgumentParser()
    111     args = get_parger(ap).parse_args()
    112     print(str(args) + "     111111111111111")
    113     basedir = os.path.dirname(os.path.realpath(__file__))
    114     print(basedir)
    115     logdir = os.path.realpath(args.script)
    116     print(logdir + "2222222")
    117 
    118     # 聚合结果
    119     results = []
    120 
    121     # 遍历所有日志
    122     for subdir in os.listdir(logdir):
    123         if os.path.isfile(os.path.join(logdir, subdir)):
    124             continue
    125         args.script = os.path.join(logdir, subdir)
    126         args.outfile = os.path.join(args.script, HTML_FILE)
    127         result = {}
    128         result["name"] = subdir
    129         result["result"] = main(args)
    130         results.append(result)
    131 
    132     # 生成聚合报告
    133     env = jinja2.Environment(
    134         loader=jinja2.FileSystemLoader(basedir),
    135         extensions=(),
    136         autoescape=True
    137     )
    138     template = env.get_template("summary_template.html")
    139     html = template.render({"results": results})
    140 
    141     output_file = os.path.join(logdir, "summary.html")
    142     with io.open(output_file, 'w', encoding="utf-8") as f:
    143         f.write(html)
    144     print(output_file)
    report.py文件

    summary_template.html文件

     1 <!DOCTYPE html>
     2 <html>
     3 <head>
     4     <title>测试结果汇总</title>
     5     <meta charset="UTF-8">
     6     <style>
     7         .fail {
     8             color: red;
     9           7emem;
    10          text-align: center;
    11         }
    12         .success {
    13             color: green;
    14           7emem;
    15          text-align: center;
    16         }
    17       .details-col-elapsed {
    18           7em;
    19          text-align: center;
    20       }
    21       .details-col-msg {
    22           7em;
    23          text-align: center;
    24          background-color:#ccc;
    25       }
    26 
    27     </style>
    28 </head>
    29 <body>
    30 <div>
    31 <div><h2>Test Statistics</h2></div>
    32 
    33     <table width="800" border="thin" cellspacing="0" cellpadding="0">
    34         <tr  width="600">
    35             <th width="300" class='details-col-msg'>案例名称</th>
    36             <th class='details-col-msg'>执行结果</th>
    37         </tr>
    38         {% for r in results %}
    39         <tr width="600">
    40             <td class='details-col-elapsed'><a href="{{r.name}}.log/log.html" target="view_window">{{r.name}}</a></td>
    41             <td class="{{'success' if r.result else 'fail'}}">{{"成功" if r.result else "失败"}}</td>
    42         </tr>
    43         {% endfor %}
    44     </table>
    45 </div>
    46 </body>
    47 </html>
    summary_template.html文件

  • 相关阅读:
    whoami
    w
    id
    su
    chpasswd
    chage
    password
    scrapy框架中Download Middleware用法
    scrapy框架持久化存储
    scrapy框架中Item Pipeline用法
  • 原文地址:https://www.cnblogs.com/zhangxue521/p/12349789.html
Copyright © 2020-2023  润新知