ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Airtest通过代码生成报告——simple_report、LogToHtml详解

2022-01-29 11:03:20  阅读:440  来源: 互联网

标签:代码生成 log script simple self file Airtest report root


上期回顾:Airtest生成报告命令行airtest report详解


以下基于
python3.8;airtestIDE1.2.11;airtest1.2.2;pocoui1.0.83

上期我们讲了在命令行生成报告,这次我们看下怎么通过脚本直接在代码中运行生成报告。分别是LogToHtml类和simple_report()函数。

LogToHtml

上期我们讲airtest report时,源码里已经看到了,最终生成报告,就是实例化LogToHtml类,并调用了里面的report()方法,那这次我们详细看下其源码。
先看下LogToHtml类的初始化

 1# 文件位置:your_python_path/site-packages/airtest/report/report.py
2class LogToHtml(object):
3    """Convert log to html display """
4    def __init__(self, script_root, log_root="", static_root="", export_dir=None, script_name="", logfile=None, lang="en", plugins=None):
5        self.log = []
6        self.script_root = script_root
7        self.script_name = script_name
8        if not self.script_name or os.path.isfile(self.script_root):
9            self.script_root, self.script_name = script_dir_name(self.script_root)
10        self.log_root = log_root or ST.LOG_DIR or os.path.join(".", DEFAULT_LOG_DIR)
11        self.static_root = static_root or STATIC_DIR
12        self.test_result = True
13        self.run_start = None
14        self.run_end = None
15        self.export_dir = export_dir
16        self.logfile = logfile or getattr(ST, "LOG_FILE", DEFAULT_LOG_FILE)
17        self.lang = lang
18        self.init_plugin_modules(plugins)

参数说明:

  • script_root:脚本所在文件夹

  • log_root:log.txt所在文件夹

  • static_root:部署静态资源的服务器路径

  • export_dir:导出报告文件夹

  • script_name:脚本名称

  • logfile:log.txt的路径

  • lang:报告的语言,中文:zh;英文:en(默认)

  • plugins:插件,使用了poco框架,需要填写--plugin poco.utils.airtest.report。如果用到了airtest-selenium,需要填写`--plugin airtest_selenium.report

源码解析:
只说下重要的
第8行:如果没有指定脚本名称,则使用script_dir_name()通过前面给的脚本所在文件夹自行获取

第10行:指定了log.txt所在文件夹则直接赋值,否则使用全局变量ST.LOG_DIR给的路径(就是说你可以在代码最开始通过全局变量指定日志路径)。如果都没有,则取当前目录下的log文件夹。

第16行:如果指定了log.txt全路径则直接赋值,否则使用全局变量ST.LOG_FILE给的路径(默认是log.txt,你可以在代码最开始通过全局变量指定日志全路径)

LogToHtml类里有各种方法去获取生成报告所需的各种数据,这里我们只看一个我们直接接触到的:

 1    def _translate_desc(self, step, code):
2        """ 函数描述 """
3        if step['tag'] != "function":
4            return None
5        name = step['data']['name']
6        res = step['data'].get('ret')
7        args = {i["key"]: i["value"] for i in code["args"]}
8
9        desc = {
10            "snapshot": lambda: u"Screenshot description: %s" % args.get("msg"),
11            "touch": lambda: u"Touch %s" % ("target image" if isinstance(args['v'], dict) else "coordinates %s" % args['v']),
12            "swipe": u"Swipe on screen",
13            "wait": u"Wait for target image to appear",
14            "exists": lambda: u"Image %s exists" % ("" if res else "not"),
15            "text": lambda: u"Input text:%s" % args.get('text'),
16            "keyevent": lambda: u"Click [%s] button" % args.get('keyname'),
17            "sleep": lambda: u"Wait for %s seconds" % args.get('secs'),
18            "assert_exists": u"Assert target image exists",
19            "assert_not_exists": u"Assert target image does not exists",
20        }
21
22        # todo: 最好用js里的多语言实现
23        desc_zh = {
24            "snapshot": lambda: u"截图描述: %s" % args.get("msg"),
25            "touch": lambda: u"点击 %s" % (u"目标图片" if isinstance(args['v'], dict) else u"屏幕坐标 %s" % args['v']),
26            "swipe": u"滑动操作",
27            "wait": u"等待目标图片出现",
28            "exists": lambda: u"图片%s存在" % ("" if res else u"不"),
29            "text": lambda: u"输入文字:%s" % args.get('text'),
30            "keyevent": lambda: u"点击[%s]按键" % args.get('keyname'),
31            "sleep": lambda: u"等待%s秒" % args.get('secs'),
32            "assert_exists": u"断言目标图片存在",
33            "assert_not_exists": u"断言目标图片不存在",
34        }
35
36        if self.lang == "zh":
37            desc = desc_zh
38
39        ret = desc.get(name)
40        if callable(ret):
41            ret = ret()
42        return ret

看到了吗,我们看的报告中的步骤描述,就是在这里定义的,如果你想修改,可以直接修改这里。

实例化LogToHtml类之后,就可以使用类中的方法report()生成报告了

 1    def report(self, template_name=HTML_TPL, output_file=HTML_FILE, record_list=None):
2        """
3        Generate the report page, you can add custom data and overload it if needed
4
5        :param template_name: default is HTML_TPL
6        :param output_file: The file name or full path of the output file, default HTML_FILE
7        :param record_list: List of screen recording files
8        :return:
9        """
10        if not self.script_name:
11            path, self.script_name = script_dir_name(self.script_root)
12
13        if self.export_dir:
14            self.script_root, self.log_root = self._make_export_dir()
15            # output_file可传入文件名,或绝对路径
16            output_file = output_file if output_file and os.path.isabs(output_file) \
17                else os.path.join(self.script_root, output_file or HTML_FILE)
18            if not self.static_root.startswith("http"):
19                self.static_root = "static/"
20
21        if not record_list:
22            record_list = [f for f in os.listdir(self.log_root) if f.endswith(".mp4")]
23        data = self.report_data(output_file=output_file, record_list=record_list)
24        return self._render(template_name, output_file, **data)

参数说明:

  • template_name:就是/your_python_path/site-packages/airtest/report/log_template.html,感兴趣可以打开看看以及看下源码。另外,你也可以传入自己的模板。

  • output_file:日志全路径,默认为log.html

  • record_list:录像文件列表

源码解析:
前面分别获取脚本路径和名称、导出文件和路径、录像列表。

之后调用report_data()方法,该方法就是获取所有报告信息的,里面调用了LogToHtml类中的很多方法去获取生成报告所需的各种各样的数据,感兴趣的可以自己看看。

最后调用并返回_render(),该方法其实就是用jinja2配合HTML模板生成报告(Jinja2是Python下的一个模板引擎,用来生成HTML网页)

可以看下_render()的实现:

 1    @staticmethod
2    def _render(template_name, output_file=None, **template_vars):
3        """ 用jinja2渲染html"""
4        env = jinja2.Environment(
5            loader=jinja2.FileSystemLoader(STATIC_DIR),
6            extensions=(),
7            autoescape=True
8        )
9        env.filters['nl2br'] = nl2br
10        env.filters['datetime'] = timefmt
11        template = env.get_template(template_name)
12        html = template.render(**template_vars)
13
14        if output_file:
15            with io.open(output_file, 'w', encoding="utf-8") as f:
16                f.write(html)
17            LOGGING.info(output_file)
18
19        return html

实例演示

 1__author__ = '公众号:测试工程师小站'
2
3from airtest.core.api import *
4from airtest.report.report import LogToHtml
5
6auto_setup(__file__,logdir=True)
7
8touch([500, 500])  # 此一句代表整个脚本
9
10r = LogToHtml(script_root=r'D:\code\Airtest\test1.air', log_root=r'D:\code\Airtest\test1.air\log', export_dir=r'D:\code\Airtest\report\test1', lang='zh')
11r.report()  # 用法1:生成报告就在导出文件夹下,名字为log.html
12
13# 用法2:所有的资源文件在导出文件夹,但HTML文件在report文件夹,且叫custom_report.html
14# 个人不建议html文件与资源文件分离,放在一起不好管理吗?
15# r.report(output_file=r'D:\code\Airtest\report\custom_report.html')

将用例代码和生成报告代码写一起,有个缺点就是用例失败后,后面的代码就不会执行了,可以加try,改造后的代码

 1__author__ = '公众号:测试工程师小站'
2
3from airtest.core.api import *
4from airtest.report.report import LogToHtml
5
6auto_setup(__file__,logdir=True)
7try:
8    touch([500, 500])  # 此一句代表整个脚本
9except:
10    print('发生异常,在这写异常处理语句,或是重新运行一遍脚本')
11finally:  # 不管脚本成功与否,都会执行finally块中的语句
12    r = LogToHtml(script_root=r'D:\code\Airtest\test1.air', log_root=r'D:\code\Airtest\test1.air\log', export_dir=r'D:\code\Airtest\report\test1', lang='zh')
13    r.report()

现在还有个问题,就是用代码生成报告,所有东西我们都写死了,这样每次报告都会相互覆盖,如果想保留每次报告,我们只需要将报告导出路径自定义一下,比如每次都导到一个新的文件夹,名字为:用例名_日期。

 1__author__ = '公众号:测试工程师小站'
2
3import time, os
4from airtest.core.api import *
5from airtest.report.report import LogToHtml
6
7auto_setup(__file__,logdir=True)
8try:
9    touch([500, 500])  # 此一句代表整个脚本
10except:
11    print('发生异常,在这写异常处理语句,或是重新运行一遍脚本')
12finally:  # 不管脚本成功与否,都会执行finally块中的语句
13    casename = os.path.basename(__file__)  # 用例名就取文件名,或者你也可以通过其他方式定义
14    casename = casename.split('.')[0]
15    dt = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())
16    dirname = casename + dt
17    r = LogToHtml(script_root=r'D:\code\Airtest\test1.air', log_root=r'D:\code\Airtest\test1.air\log', export_dir=dirname, lang='zh')
18    r.report()

simple_report()

simple_report()与LogToHtml类在同一个文件中,是一个独立的函数。

1# 文件位置:your_python_path/site-packages/airtest/report/report.py
2def simple_report(filepath, logpath=True, logfile=None, output=HTML_FILE):
3    path, name = script_dir_name(filepath)
4    if logpath is True:
5        logpath = os.path.join(path, getattr(ST, "LOG_DIR", DEFAULT_LOG_DIR))
6    rpt = LogToHtml(path, logpath, logfile=logfile or getattr(ST, "LOG_FILE", DEFAULT_LOG_FILE), script_name=name)
7    rpt.report(HTML_TPL, output_file=output)

参数说明:

  • filepath:对应的是LogToHtml初始化时的script_root参数,脚本文件的全路径,可以直接传入变量__file__

  • logpath:对应的是LogToHtml初始化时的log_root参数。布尔值,为True时,使用全局变量ST.LOG_DIR给的路径(就是说你可以在代码最开始通过全局变量指定日志路径),如果都没有,则取当前目录下的log文件夹

  • logfile:对应的是LogToHtml初始化时的logfile参数,log.txt的文件路径

  • output:对应的是report()方法中的output_file参数,报告导出全路径,必须以.html结尾

源码解析:
第1行获取脚本路径;
第2、3行获取日志路径;
第5行实例化LogToHtml;
第6行调用LogToHtml类的report()方法生成报告。

代码逻辑很简单,实际上调用的还是LogToHtml。但是使用simple_report()无法导出报告,只能在本地查看。

实例演示
我个人觉得simple_report()码如其名,就是给大家一个最简单的生成报告的方法。所以我个人觉得使用时就应该全用默认值参数:

 1__author__ = '公众号:测试工程师小站'
2
3from airtest.core.api import *
4from airtest.report.report import simple_report
5
6auto_setup(__file__,logdir=True)
7
8touch([500, 500])  # 此一句代表整个脚本
9 # 其他参数全用默认的,即在当前脚本路径下生成名为log.html的报告
10simple_report(__file__)

以上就是LogToHtml类和simple_report()函数的使用了。但如果你有意将自动化做的正规且容入项目流程中,那必然要涉及CI,比如用Jenkins自动执行。如果要自动执行,那就还是得用命令行调用的方法(airtest run、airtest report)。
所以本篇内容不建议你实用,仅做为了解生成报告的内在逻辑学习,实用的还是看看前2期的airtest run、airtest report。

 

---------------------------------------------------------------------------------

关注微信公众号即可在手机上查阅,并可接收更多测试分享~

标签:代码生成,log,script,simple,self,file,Airtest,report,root
来源: https://www.cnblogs.com/songzhenhua/p/15854502.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有