Skip to content

二、Airtest启动器介绍

注解

主要描述编写录制脚本中,涉及到启动器部分和自定义参数的内容,可能未来会因为airtest的迭代而发生改动

在编写测试脚本的过程中,经过airtest封装的简单语句可能满足不了更复杂的代码编写需求,这一章主要介绍脚本编写中的一些高级特性。

Airtest脚本目前支持的自定义功能有:

  • 设置脚本运行过程中的参数
  • 添加自定义方法,或者替换默认方法
  • 在测试用例的运行前后,执行初始化代码或清理代码,甚至是调用其他用例脚本

1. 启动器介绍

Airtest在运行用例脚本时,在继承 unittest.TestCase 的基础上,实现了一个叫做 AirtestCase 的类,添加了所有执行基础Airtest脚本的相关功能。

因此,假如需要添加自定义功能,只需要在 AirtestCase 类的基础上,往 setupteardown 中加入自己的代码即可。如果这些设置和功能内容相对固定,可以将这些内容作为一个launcher,用来在运行实际测试用例之前初始化相关的自定义环境。

AirtestCase 的内容详情介绍可参考:Airtest帮助文档的相关内容

2. 启动器范例

以下是一个自定义custom_launcher.py的范例代码:

    from airtest.cli.runner import AirtestCase, run_script
    from airtest.cli.parser import runner_parser


    class CustomAirtestCase(AirtestCase):

        def setUp(self):
            print("custom setup")
            # add var/function/class/.. to globals
            # self.scope["hunter"] = "i am hunter"
            # self.scope["add"] = lambda x: x+1

            # exec setup script
            # self.exec_other_script("setup.owl")
            super(CustomAirtestCase, self).setUp()

        def tearDown(self):
            print("custom tearDown")
            # exec teardown script
            # self.exec_other_script("teardown.owl")
            super(CustomAirtestCase, self).setUp()


    if __name__ == '__main__':
        ap = runner_parser()
        args = ap.parse_args()
        run_script(args, CustomAirtestCase)

它的主要功能就是:在AirtestCase的基础上,添加了一些自定义的内容,同时可以通过它作为一个启动器,来运行实际的测试用例代码。

例如:

 python custom_launcher.py test.air --device Android:///serial_num --log log_path

这个命令行使用自定义的启动器custom_launcher.py来运行名为test.air的脚本。

3. Airtest-IDE中的启动器

在IDE中,运行脚本的方式有两种,第一种是简单地在编辑框里写上要运行的Airtest代码,之后就能够用默认方式来运行脚本,无需其他额外的代码。

第二种,就是在刚才介绍的启动器基础上,实现一个自定义的启动器,这样能够初始化一个自定义的环境,供后来编写的Airtest代码运行。

1)配置方法

菜单-“选项”-“设置”-“Airtest”,点击“自定义Launcher文件位置”右侧的设置框,即可打开文件选择窗口,选择自定义的launcher.py文件即可。

点击“编辑”,可对launcher.py文件的内容进行编辑,点击右下角的“OK”按钮让新配置生效。

2)代码范例

以下是一份 在AirtestIDE中 使用的启动器代码范例(与上文那份命令行可直接运行的 启动器范例 相比,IDE下可以把当前运行的代码行标出颜色,以及未来可能还可以额外支持其他功能):

    from airtest.cli.runner import run_script
    from airtest.cli.parser import runner_parser
    from airtest.core.settings import Settings as ST
    # 假如脚本在IDE中运行,IDE会自动帮忙加载AirtestCase。假如要用命令行独立运行脚本,则需要手工import AirtestCase
    if not global().get("AirtestCase"):
        from airtest.cli.runner import AirtestCase

    class CustomAirtestCase(AirtestCase):
        def __init__(self):
            super(CustomAirtestCase, self).__init__()

        def setUp(self):
            print("custom setup")
            super(CustomAirtestCase, self).setUp()

        def tearDown(self):
            print("custom tearDown")
            super(CustomAirtestCase, self).tearDown()

    if __name__ == '__main__':
        ap = runner_parser()
        args = ap.parse_args()
        run_script(args, CustomAirtestCase)

4. 启动器中自定义内容介绍

在自定义的启动器代码中,继承 AirtestCase 之后,能够在setUp()tearDown()方法里对执行脚本时的环境变量进行设置:

        class CustomAirtestCase(AirtestCase):
            def setUp(self):
                # add var/function/class/.. to globals
                super(CustomAirtestCase, self).setUp()

1) 添加自定义变量与方法

将自定义变量添加到 self.scope 里,之后用该启动器来运行Airtest的脚本,脚本代码中就能够直接使用这些变量,无需重新定义:

        def setUp(self):
            self.scope["hunter"] = "i am hunter"
            self.scope["add"] = lambda x: x+1

2)在正式脚本运行前后,添加子脚本的运行

在执行测试用例时,有一类很常见的需求,是在正式用例之前执行固定的初始化脚本,或是在用例执行完毕后执行清理脚本.

在自定义Airtest启动器中,可以使用很简单的代码来完成这类需求:

        class CustomAirtestCase(AirtestCase):
            PROJECT_ROOT = "子脚本存放公共路径"  # 可以将子脚本放置在某个公共目录下

            def setUp(self):
                # exec setup script
                self.exec_other_script("setup.air")  # 假设该setup.air脚本存放在PROJECT_ROOT目录下,调用时无需填写绝对路径,可以直接写相对路径
                super(CustomAirtestCase, self).setUp()

            def tearDown(self):
                # exec teardown script
                self.exec_other_script("teardown.air")
                super(CustomAirtestCase, self).setUp()

3)在正式脚本里,添加子脚本的运行

另一类常见需求是在脚本内执行子脚本,同样可以将子脚本存放在 PROJECT_ROOT 公共目录下,然后在脚本 test.air 中调用代码:

        exec_script("子脚本.air")

4)修改Airtest默认参数值

Airtest在运行脚本和识别图像的过程中,由于默认配置的参数值可能不符合实际运行需要,以下代码演示了如何修改默认参数配置:

        from airtest.core.settings import Settings as ST

        class CustomAirtestCase(AirtestCase):
            def setUp(self):
                ST.THRESHOLD = 0.75

上面这段代码,将默认配置的图像识别准确率阈值改为了0.75(默认值是0.6),降低了图像识别的错误率。

airtest.core.settingsSettings 中,有以下配置选项可以进行修改:

THRESHOLD 图像识别精确度阈值,0~1之间,越大表示识别精度越高
THRESHOLD_STRICT assert语句里图像识别时使用的高要求阈值,默认为0.7
RESIZE_METHOD 可以对图像识别时的UI跨分辨率规律进行重定义
LOG_DIR 脚本运行log存放路径,默认为脚本当前路径
LOG_FILE 运行log的存放文件名,默认为log.txt
OPDELAY 每一步操作后等待多长时间进行下一步操作,默认0.1s
FIND_TIMEOUT 进行图像查找时的超时时间,默认为20s

5)注册自定义设备,实现更多复杂操作

在Airtest中,默认支持三种设备:Android, Windows和IOS,在执行脚本的命令行中通过参数 --device Android:/// 来指定脚本运行在某一类型设备上。

假如需要对这些设备的某些运行操作进行修改,可以自行实现一种新的设备,并将它注册到Airtest中,即可在运行脚本的时候调用了。

例如,当IDE中的Airtest脚本运行在Windows模式下时,由于截图大小的问题需要对Airtest的Windows代码进行一些修改。因此IDE实现了一个新的类,名为WindowsInIDE:

        from airtest.core.win.win import Windows, screenshot
        class WindowsInIDE(Windows):
            def snapshot(self, filename="tmp.png"):
                # 实现了IDE相关的特殊截图操作
                pass

    然后,在启动器中将这个WindowsInIDE注册到Airtest中::

        class AirtestIDECase(AirtestCase):
        """单独在IDE中使用,添加了windows相关的特殊处理"""
        def __init__(self):
            if get_platform() == "Windows":
                import WindowsInIDE
                # 注册一种ide专属的windows模式设备到airtest中
                from airtest.core.api import G
                G.register_custom_device(WindowsInIDE)
            super(AirtestIDECase, self).__init__()

注册后,在执行脚本时,修改运行指令中的device参数,就能使用刚才注册的新设备名称来运行脚本了:

        python launcher.py test.air --device WindowsInIDE:///

5. 总结:实现自定义启动器的步骤

自定义启动器可以进行配置项的修改和实现更多复杂需求,类似于 unittest ,能够将原先的Airtest脚本作为测试用例来运行。

在IDE中,若想实现一个自定义启动器的步骤如下:

  • 新建一个 custom_launcher.py 文件,在里面实现一个继承了 AirtestCase 的类。

  • setUp()tearDown() 中,添加上自己想要实现的操作。

  • 在IDE的选项-配置-Airtest配置中,将刚才实现的 custom_launcher.py 设置为启动器。

  • 直接点击运行脚本即可。或者使用命令行的方式运行:python custom_launcher.py test.air airtest脚本参数

6. 拓展:启动器的应用实例

Airtest启动器的应用实例,可以参考官方公众号AirtestProject的往期推文: