airtest源码分析—air脚本的运行过程runner.py

概述

本次是分析airtest的运行过程,通过分析我们将知道airtest是怎么运行.air文件脚本的

入口

关键代码有两个地方,一个是main文件,作为接收命令行参数,另一个是/core/cli/runner.py文件里面

先来看看main.py文件

def main(argv=None):
    ap = get_parser()
    args = ap.parse_args(argv)
    if args.action == "info":
        from airtest.cli.info import get_script_info
        print(get_script_info(args.script))
    elif args.action == "report":
        from airtest.report.report import main as report_main
        report_main(args)
    elif args.action == "run":
        from airtest.cli.runner import run_script
        run_script(args)
    elif args.action == "version":
        from airtest.utils.version import show_version
        show_version()
    else:
        ap.print_help()

这个比较简单,就是处理传参的,参考官方文档我们一般执行脚本是通过:

airtest run untitled.air --device Android:///手机设备号 --log log/

所以执行脚本是通过run参数,run参数再调用runner.py文件的run_script方法,因此呢我们可以自定义执行脚本,只需要接收参数并调用run_script方法即可,此处官方文档已经给出了自定义启动器的教程,我们已经知道原理了,直接照着官方文档走就行了,传送门

core/cli/runner.py

接下来我们就开始具体分析这个文件

打开这个方法

def run_script(parsed_args, testcase_cls=AirtestCase):
    global args  # make it global deliberately to be used in AirtestCase & test scripts
    args = parsed_args
    suite = unittest.TestSuite()
    suite.addTest(testcase_cls())
    result = unittest.TextTestRunner(verbosity=0).run(suite)
    if not result.wasSuccessful():
        sys.exit(-1)

嗯,有种熟悉感,本质就是unitest框架,把testcase装进suite,然后定义runner执行即可,这里没办法解释是怎么运行.air的,所以线索就在默认参数AirtestCase这个类里面,这个同样定义在runner.py文件中

AirtestCase

最上面有几个初始化的test fixture方法setUpClass、setUp、tearDown,基本作用就是初始化设备参数,

    @classmethod
    def setUpClass(cls):
        cls.args = args

        setup_by_args(args)

        # setup script exec scope
        cls.scope = copy(globals())
        cls.scope["exec_script"] = cls.exec_other_script

    def setUp(self):
        if self.args.log and self.args.recording:
            for dev in G.DEVICE_LIST:
                try:
                    dev.start_recording()
                except:
                    traceback.print_exc()

    def tearDown(self):
        if self.args.log and self.args.recording:
            for k, dev in enumerate(G.DEVICE_LIST):
                try:
                    output = os.path.join(self.args.log, "recording_%d.mp4" % k)
                    dev.stop_recording(output)
                except:
                    traceback.print_exc()

这几个方法基本就是初始化参数的作用了,包括设备参数,安卓端的视频录制参数这些,核心的方法还是runTest方法,这也是unitest框架的测试执行方法

    def runTest(self):
        scriptpath, pyfilename = script_dir_name(self.args.script)
        pyfilepath = os.path.join(scriptpath, pyfilename)
        pyfilepath = os.path.abspath(pyfilepath)
        self.scope["__file__"] = pyfilepath
        with open(pyfilepath, 'r', encoding="utf8") as f:
            code = f.read()
        pyfilepath = pyfilepath.encode(sys.getfilesystemencoding())

        try:
            exec(compile(code.encode("utf-8"), pyfilepath, 'exec'), self.scope)
        except Exception as err:
            tb = traceback.format_exc()
            log("Final Error", tb)
            six.reraise(*sys.exc_info())

主要有两个作用:

  1. 解析传入的xx.air的路径和实际.py
  2. 通过exec执行.py文件,运行脚本

那么分析到这里也就明白了执行airtest run xxx.air实际上是exec执行了.py文件

你可能感兴趣的:(airtest源码分析—air脚本的运行过程runner.py)