Appium UiAutomator2驱动:被测应用(APP)能
Appium
服务端会提供的一系列能力集合,Appium
客户端通过构造键值对集合并发送给Appium
服务端,以此来告诉服务器需要提供什么样的能力(例如建立与何种设备的通信,是Android
还是ios
设备、建链的超时时间等),也可以在运行过程中对服务端的行为进行修改。
Appium
提供的能力跟Driver
相关,不同的Driver
对应不同的测试对象,提供的能力以及所需要传入的参数都不一样,本文描述的是UiAutomator2 Driver
提供的能力集合,它提供对Android
设备的自动化测试支持。按照官方文档的定义,分为通用能力、Driver/Server
能力等方面,本文介绍UiAutomator2
提供的与被测应用相关的力能力集。
本文所有测试代码的前提是已经安装Appium
和相关环境(例如JDK
、Android SDK
、AVD
模拟器),可以参考Appium
环境搭建。
一、被测应用(APP
)能力
如下参数主要是用于操作被测设备上对被测应用。
能力名称 | 具体描述 |
---|---|
appium:app |
可选,表示被测应用的全路径(必须和运行的Appium 服务端在同一个机器上)。可以支持apk 和apks 两种扩展,以及通过URL 指定的远程位置。如果appium:app 、appium:appPackage 或browserName 三个参数均未提供,那么UiAutomator2 驱动会从Dashboard 开始启动,需要测试脚本去指定下一步动作。注意:appium:app 和browserName 不能同时提供。 |
browserName |
可选,运行测试的浏览器,如果提供了该参数,UiAutomator2 Driver 会默认在Web 上下文模式中启动测试(默认是原生模式),通常可以设置为chrome 。 |
appium:appPackage |
可选,被测应用程序的包标识符,如果该参数未提供,则UiAutomator2 Driver 会从appium:app 参数中尝试自动获取。 |
appium:appActivity |
可选,主应用活动标识符,如果未提供,UiAutomator2 Driver 会从appium:app 参数中尝试自动获取。appium:appPackage 和appium:appActivity 的获取方式可以参考这里
|
appium:appWaitActivity |
可选,等待启动的第一个活动标识符,如果该参数未设置,则等价于appium:appActivity 。 |
appium:appWaitPackage |
可选,等待启动的第一个应用程序标识符,如果该参数未提供,则等价于appium:appPackage 。 |
appium:appWaitDuration |
可选,被测应用启动的最大等待时间(应用活动的控制前返回到调用者),单位是毫秒,默认值是20000 。 |
appium:androidInstallTimeout |
可选,被测应用安装的最大等待时间,单位是毫秒,默认是90000 。 |
appium:appWaitForLaunch |
可选,应用活动被Activity Manger 启(am 命令)动之后,在控制权返到调用者(测试脚本)之前,调用者是否要阻塞并等待。默认是true (如果设置为false ,调用者侧的测试会继续执行,而不会阻塞等待)。 |
appium:intentCategory |
可选,通过Activity Manger 启动活动时,通过该参数指定的intent 类别(categories ),默认为android.intent.category.LAUNCHER 。没有设置显式值的话请使用mobile:startActivity 。备注:intent 在此处是一个有专门含义的词,在Android 中用于启动活动(activity ),intent 可以附加一些选项来启动活动,本参数就是其中的选项之一,可以参考本文第二部分对activity 和intent 的介绍了解更多。 |
appium:intentAction |
可选,通过Activity Manger 启动活动时,通过该参数指定的intent 动作(action ),默认为android.intent.action.MAIN 。若没有设置显式值请使用mobile:startActivity 。 |
appium:intentFlags |
可选,通过Activity Manger 启动活动时,通过该参数指定的intent 标记,默认为0x10200000 (FLAG_ACTIVITY_NEW_TASK)`。 |
appium:optionalIntentArguments |
可选,通过Activity Manger 启动活动时,通过该参数指定的intent 参数。 |
appium:dontStopAppOnReset |
可选,当设置为true ,可以避免正在运行的被测应用被重启。当appium:noReset 被设置为false ,那么被测应用在如下两种情况下会被重启:1)当该参数设置为false ,或2)appium:forceAppLaunch 被设置为true 。该参数默认为false 。 |
appium:forceAppLaunch |
可选,当设置为true ,被测应用在每次会话启动的时候都会被强制重启(即使appium:noReset 被设置为true 且被测应用也正在运行)。当appium:noReset 被设置为false ,那么被测应用在如下两种情况下会被重启:1)appium:dontStopAppOnReset 被设置为false (默认值),或2)本参数被设置为true 。本参数默认为false ,UiAutomator2 驱动2.12 版本开始支持。 |
appium:shouldTerminateApp |
可选,当设置为true ,被测应用在会话结束时会被关闭(即使appium:noReset 的值是true )。当appium:noReset 和appium:dontStopAppOnReset 均被设置为false 时,被测应用会被关闭。该值默认为false 。 |
appium:autoLaunch |
可选,当设置为true 时在测试开始时候自动启动被测应用,该值默认是true 。 |
appium:autoGrantPermissions |
可选,当设置为true 时,在测试开始时自动授予全部请求的应用程序权限。要保证这一点,对版本的要求如下:1)被测应用manifest 中的targetSdkVersion 必须大于等于23 ,2)被测设备的Android 版本必须大于等于Android 6 (API level 23 )。被测应用的targetSdkVersion 若低于23 ,则需要重新安装,例如对于Android 6+ 设备将appium:fullReset 设置为true 。如果被测应用需要特定的权限,例如对通知和媒体记录的访问,考虑用appops 目标的mobile: changePermissions 扩展。 |
appium:otherApps |
可选,允许设置一个或多个逗号分隔Android 安装包路径,这些包会跟被测应用程序一起安装。当被测应用程序对其他程序有依赖,需要设置这个参数。 |
appium:uninstallOtherPackages |
可选,允许设置一个或多个逗号分隔包标识符,这些包会在测试运行前从被测设备中卸载。 |
appium:allowTestPackages |
可选,如果设置为true ,则能在自动化测试中使用以测试标志构建的包(通过使用adb install -t 命令)。该值默认是false 。 |
appium:remoteAppsCacheLimit |
可选,测试过程中可以缓存到被测设备上的应用安装包最大数量。对于那些不支持流式安装的设备(Android 7 及以下),ADB 必须把包先推送到设备然后才能安装,因此需要消耗一些时间,需要配置该参数。可以通过设置该参数为0 来禁止应用包缓存功能,该参数的默认值是10 。 |
appium:enforceAppInstall |
可选,如果设置为true ,即使设备上的被测应用是更新的版本,该应用也会被强制重新安装。当appium:noReset 参数设置为true 时,本参数会不起作用。本参数默认值是false 。 |
APP
本地化能力集:
能力名称 | 具体描述 |
---|---|
appium:localeScript |
可选,被测应用的规范化本地名称,例如zh-Hans-CN 中的Hans 。更多细节可以参考https://developer.android.com/reference/java/util/Locale.html。 |
appium:language |
可选,指定提取被测应用字符串的语言名称,默认情况下,使用当前系统语言提取被测应用字符串。更多细节参考https://developer.android.com/reference/java/util/Locale.html。 |
appium:locale |
可选,为被测应用设置区域。如果设置了本参数,那么同时也需要提供appium:language 参数。 |
二、能力解析
-
关于
Android
中activity
和intent
的概念activity
:activity
是Android
应用程序的核心和基础概念,这里翻译成活动
。可以把Android
应用看成是一系列活动组成的,每个活动都可以进入和退出。活动可以简单类比成当前呈现出来的"屏幕",在当前屏幕中呈现出来的各种界面元素共同组成一个活动。要从当前屏幕呈现的界面切换到下一个,需要启动一个新的活动。从当前活动切换到下一个活动,并不局限只能在一个应用中,切换活动后,造成的结果可能是启动了一个新的应用。活动概念被设计出来主要是方便应用之间传递信息或复用。比如摄像机拍摄活动可以被各种应用启动,而不需要每个应用在需要改功能的时候单独去写一个摄像机拍摄的功能。如果已经连接上Android
设备,可以使用adb
提供的am
命令(Activity Manger
的缩写)来启动一个活动(-n
参数指定名称),例如启动联系人列表:adb shell am start -n com.google.android.dialer/.extensions.GoogleDialtactsActivity
intent
:活动都是通过intent
来启动的,这里翻译成意图
,意图有两种类型:显式意图和隐式意图。显式意图是通过应用的名称和活动的名称(在应用的manifest
文件中申明)来启动一个活动;隐式意图用于在单个应用内进行活动的切换。显式意图是直接指定应用的名称和活动的名称来启动一个活动;隐式意图则是通过已定义好用户意图来启动活动,例如指定启动活动的意图是
android.intent.action.SET_WALLPAPER
,那么Android
系统会在设备上查找所有应用的所有活动,找到申请支持该意图的活动,然后启动该活动。如果找到支持意图的活动只有一个,那直接启动该活动即可,如果找到支持该意图的活动有多个呢?Android
会所有支持该意图的活动弹出来让用户进行选择。在本文使用的模拟器设备上,执行adb shell am start -a android.intent.action.SET_WALLPAPER
(-a
参数表明这是一个动作意图)会出现3
个支持该意图的活动供选择。更多细节可以参考文章What Appium Users Need to Know about Android Activities and Intents
关于意图的更多参数介绍请参考这里。
-
通过设置
appium:appPackage
和appium:appActivity
启动一个指定应用
# -*- coding: utf-8 -*-
import pytest
from appium import webdriver
from appium.options.android import UiAutomator2Options
from appium.webdriver.appium_service import AppiumService
import time
import datetime
# 开启服务端
APPIUM_HOST = '127.0.0.1'
APPIUM_PORT = 4723
@pytest.fixture(scope="session")
def start_appium_service():
server = AppiumService()
server.start(args=['--address', APPIUM_HOST, '-p', str(APPIUM_PORT)], timeout_ms=60000)
yield server
server.stop()
# 创建客户端到服务端的会话
def create_appium_session_by_api(custom_opts = None):
options = UiAutomator2Options()
if custom_opts is not None:
options.load_capabilities(custom_opts)
return webdriver.Remote(f'http://{AP_intentPIUM_HOST}:{APPIUM_PORT}', options=options)
def test_app_capability_explicit_intent(start_appium_service):
driver = create_appium_session_by_api()
driver.start_activity("com.google.android.dialer", ".extensions.GoogleDialtactsActivity")
-
通过
appium:appWaitActivity
和appium:appWaitPackage
等待第一个被启动的应用和活动下面的代码会等待消息发送应用和活动打开,如果一直未等到该界面打开,那么会提示超时异常(超时时间通过
appium:appWaitDuration
指定,默认是20S
),因此在启动下面的测试后,在超时时间之内,需要在命令行执行adb shell am start -n com.google.android.apps.messaging/.ui.ConversationListActivity
以保证用例通过:
def test_app_capability_appWaitActivity(start_appium_service):
custom_opts = {
"appium:appWaitPackage": "com.google.android.apps.messaging",
"appium:appWaitActivity": ".ui.ConversationListActivity",
}
driver = create_appium_session_by_api(custom_opts)
assert driver.current_activity == custom_opts["appium:appWaitActivity"]
实际上,appium:appWaitActivity
和appium:appWaitPackage
支持通配符处理。
- 强制关闭被测应用
def test_app_capability_closeAppAfterSession(start_appium_service):
custom_opts = {
"appium:noReset": True,
"appium:appPackage": "com.google.android.apps.messaging",
"appium:appActivity": ".ui.ConversationListActivity",
"appium:shouldTerminateApp": True
}
driver = create_appium_session_by_api(custom_opts)
assert driver.current_activity == custom_opts["appium:appActivity"]
driver.quit()
# 被测应用在上一步会话退出时已经被关闭了
driver = create_appium_session_by_api({"appium:noReset": True})
assert driver.current_activity != custom_opts["appium:appActivity"]