Airtest一:批量運行腳本、彙總報告、導出報告

 
 

1、項目目錄

 

 

2、各文件說明

一、air_case。須要執行的腳本air文件,例如login.air。後續直接添加該文件便可,其餘的文件都不用動
 
二、export_log。該文件夾自動生成,是自動導出的日誌,發給其餘人的時候,直接發送該包,日誌中的路徑用的相對路徑。能夠直接找到文件
 
三、log。該文件夾自動生成,是運行中產生的log.txt文件
 
四、my_runner.py。運行case的啓動器,整個demo的入口文件。【通常報錯的都是這個文件】已經將這個文件改爲使用導出模板的方式
 
五、report.py。生成報告入口,可是my_runner.py已經運行完case,生成了報告,無需再執行此文件
 
六、summary_template.html。彙總報告的模版,執行完case彙總的報告是根據該文件的樣式產生的。
 
七、util.py。工具
 

3、運行方式

python3 my_runner.py
 

4、 說明

個人demo是基於圖像識別的瀏覽器case,沒有鏈接設備,執行手機的在my_runner.py將devices添加進去便可
 

5、各文件源碼

 

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  width: 7emem; 10          text-align: center; 11  } 12  .success { 13  color: green; 14  width: 7emem; 15          text-align: center; 16  } 17       .details-col-elapsed { 18  width: 7em; 19          text-align: center; 20  } 21       .details-col-msg { 22  width: 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文件
相關文章
相關標籤/搜索