三、airtest批量执行用例
我们编写的用例不可能只有一个,执行起来也不可能是单个执行,需要批量执行用例,所有本片文档针对如何批量执行用例作说明。
1、项目结构确定,一般项目尽量按照固定结构来设计,有利于批量执行用例和项目用例的维护。项目的结构需要按照如下图所示的结构来设计,下图项目是我以前做的项目结构。
批量执行用例在airtestIDE上是无法实现的,IDE只能单用例执行,所以这里通过脚本来实现。完整代码如下所示:
# -*- coding: utf-8 -*-import unittest
import os
import sys
import six
import traceback
import types
import time
from io import open
from airtest.cli.parser import runner_parser
from airtest.core.api import G, auto_setup, log
from airtest.core.settings import Settings as ST
from airtest.utils.compat import decode_path
from copy import copyclass MyAirtestCase(unittest.TestCase):@classmethoddef setUpClass(cls):cls.args = argssetup_by_args(args)# setup script exec scopecls.scope = copy(globals())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()# 设置日志路径auto_setup(logdir=self._logdir)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()def runTest(self):try:# 调用脚本中的runCase方法并传递scope供脚本使用self.runCase(self.scope)except Exception as err:tb = traceback.format_exc()log("Final Error", tb)six.reraise(*sys.exc_info())@propertydef logdir(self):return self._logdir@logdir.setterdef logdir(self, value):self._logdir = valuedef setup_by_args(args):# init devicesif isinstance(args.device, list):devices = args.deviceelif args.device:devices = [args.device]else:devices = []print("do not connect device")# set base dir to find tplargs.script = decode_path(args.script)# set log dirif args.log is True:print("save log in %s/log" % args.script)args.log = os.path.join(args.script, "log")elif args.log:print("save log in '%s'" % args.log)args.log = decode_path(args.log)else:print("do not save log")# guess project_root to be basedir of current .air pathproject_root = os.path.dirname(args.script) if not ST.PROJECT_ROOT else None# 此处不设置日志路径,防止生成多余的log.txtauto_setup(args.script, devices, None, project_root)def new_case(py, logdir):"""实例化MyAirtestCase并绑定runCase方法"""with open(py, 'r', encoding="utf8") as f:code = f.read()obj = compile(code.encode("utf-8"), py, "exec")ns = {}ns["__file__"] = py# exec obj in nsexec(obj, ns)func = ns["runCase"]case = MyAirtestCase()pyfilename = os.path.basename(py).replace(".py", "")# 设置属性以便在setUp中设置日志路径case.logdir = os.path.join(logdir, pyfilename)# 绑定runCase方法case.runCase = types.MethodType(func, case)return casedef init_log_folder():"""初始化日志根目录"""name = time.strftime("log_%Y%m%d_%H%M%S", time.localtime())if not os.path.exists(name):os.mkdir(name)return namedef run_script(parsed_args, testcase_cls=MyAirtestCase):global args # make it global deliberately to be used in MyAirtestCase & test scriptsargs = parsed_argsdir = os.path.dirname(os.path.realpath(__file__))suites = []pys = []# 获取所有用例集for f in os.listdir(dir):if f.endswith("用例集"):f = os.path.join(dir, f)if os.path.isdir(f):suites.append(f)# 获取所有脚本for s in suites:for f in os.listdir(s):if f.endswith(".py") and not f.startswith("__"):pys.append(os.path.join(s, f))logdir = os.path.join(dir, init_log_folder())args.log = logdirsuite = unittest.TestSuite()# 添加脚本for py in pys:case = new_case(py, logdir)suite.addTest(case)result = unittest.TextTestRunner(verbosity=0).run(suite)if not result.wasSuccessful():sys.exit(-1)if __name__ == "__main__":ap = runner_parser()args = ap.parse_args()run_script(args, MyAirtestCase)
下面对逻辑进行说明:
2、继承TestCase实现测试用例类,run_script方法的测试类是MyAirtestCase,而MyAirtestCase继承unittest的TestCase类。其中setUpClass和setUp方法是用例执行前进行设备、参数的设置;runTest真正开始执行用例,tearDown方法在用例执行完毕后,输出log。

3、实例化MyAirtestCase,将项目下所有的py代码用例绑定到MyAirtestCase的runCase方法中,最后返回测试用例。

4、遍历读取用例并将用例加入测试套件中,在run_script方法里面找到所有的脚本,然后将脚本添加到unittest的测试套件里面,最后通过执行测试套件来实现。下面是是核心的执行方法。附件中是全部runner代码。

5、最后,通过main函数入库开始执行用例即可,其中runner_parser是airtest.cli.parser下运行时添加到log中的参数。实现的具体方法是runner_parser。

runner_parser实现log参数数据设置。在run_scrpit中会有调用到。代码如下所示。

通过上面几步,就可以实现免IDE实现批量运行了,当然,如果想要多机器批量运行的话,此脚本还不能实现,需要另外实现多线程调度实现,这里先不做介绍,后续继续接受设置report报告。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
