# 1.2 在Android手机上进行测试 ## 1. 连接Android手机 关于`Android`手机的连接方法,可以查阅我们的[设备连接文档](../2_device_connection/1_android_phone_connection.html),若在连接过程中遇到问题请查阅[FAQ](../2_device_connection/2_android_faq.html)获取更多帮助。 在成功连上手机后(也就是说,在AirtestIDE中必须要能够顺利看到手机画面和操作手机,才算是连接成功),我们就可以开始顺利地编写脚本内容了。 ### 指定运行某台手机 假设我们已经熟练掌握连接手机的方法,并且写出了一个简单的脚本后,现在我们迫不及待地想要让脚本在手机上跑起来了,应该怎么做呢? 首先,假如你使用了AndroidIDE,现在想要**让当前脚本在当前连接的手机上运行**的话,只需要轻点“运行”按钮,或者按下快捷键`F5`,就可以看到脚本开始运行了。 其次,在AirtestIDE中点下运行按钮时,下方的log窗口会打印出一个脚本执行的命令行,类似这样: ``` "D:\AirtestIDE\AirtestIDE" runner "untitled.air" --device Android://127.0.0.1:5037/F8UDU16409004135 --log "D:\log" ``` 关于命令行执行脚本的细节,请参阅文档的脚本运行章节。在这里我们只需要重点关注`--device Android://127.0.0.1:5037/F8UDU16409004135`这个参数,它将我们想要指定的本机连接的序列号为`F8UDU16409004135`的手机传给了`Airtest`,让它明白我们需要初始化这台手机。 在连接串`Android://:/`里, adbhost是adb server所在主机的ip,adb port默认是5037,serialno是android手机的序列号。更多adb的方面的内容请参考文档[developer.google](https://developer.android.com/studio/command-line/adb)。 最后,假如我们在命令行运行脚本时并没有指定手机,我们希望在脚本内通过代码来连接手机,可以使用`connect_device`接口: ```python from airtest.core.api import connect_device # 传入连接串 dev = connect_device('Android://:/') ``` ### 多机协作 在我们编写的脚本里,支持同时连接多台手机,来编写一个“多机协作”脚本,例如让两台手机登录同一个APP并相互“添加好友”。 假如我们现在正在使用AirtestIDE编写脚本,同时连上多台手机,在运行脚本的时候AirtestIDE将会自动添加多个`--device`参数,把当前连接的手机都告诉脚本,无需其他额外操作。 否则的话,可以直接在脚本里使用多个上述的`connect_device`语句,分别传入手机连接串信息即可。 ```python from airtest.core.api import connect_device dev1 = connect_dev("Android://127.0.0.1:5037/serialno1") # 连上第一台手机 dev2 = connect_dev("Android://127.0.0.1:5037/serialno2") # 第二台手机 # 此时设备列表为[dev1, dev2],传入数字0切换当前操作的手机到第1台 set_current(0) # 切换当前操作的手机到序列号为serialno2的手机 set_current("serialno2") ``` ## 2. 手机设备的相关操作 我们在`Android`设备上进行测试时,还可能会需要获取部分设备/App相关的信息,或是执行`ADB`指令并获取输出结果。在`Airtest`中,我们除了一些常见接口之外,还封装了不少`Android`独有的接口来方便脚本在`Android`平台上运行。 例如,我们可能会希望在脚本开始的时候,先将待测APP启动: ```python from airtest.core.api import * start_app('package_name') ``` 在这段示例代码中使用的`start_app`接口是平台通用的接口,也就是说,不仅仅在`Android`上可以用来启动对应的APP,在`Windows`和`iOS`平台上也可以用这个接口来启动对应的应用程序,具体支持的平台信息可以通过查阅[start_app接口文档](https://airtest.readthedocs.io/en/latest/all_module/airtest.core.api.html#airtest.core.api.start_app)里的`Platforms`字段来获取。 在这里我们只需要使用`from airtest.core.api import *`这行代码来将`airtest.core.api`中定义的`API`引入,即可使用`Airtest`封装好的常用`API`了。 **注意:** AirtestIDE中新建脚本时会自动添加这一行,请不要删除,否则airtest的api将不能使用! ### Android设备接口 在上一段教程中我们提到过了可以使用`connect_device`来连接手机并获取到连接后的`Device`对象,我们也可以通过`device()`接口获取到当前操作的`Device`对象进行操作。 接下来的第二个例子是,假如我们想要列出**当前已连接**的`Android`手机设备上所有已安装的APP列表,我们可以这样写: ```python # 获取当前连接中的手机 dev = device() # 打印出app列表 print(dev.list_app()) ``` 例子中所使用到的`list_app`是`airtest.core.android.android`中,设备对象`Android`的独有接口,我们还封装了不少常用的安卓操作可供调用,例如`install_app`,`get_top_activity()`等,具体可以查阅`airtest.core.android.android`的[文档](http://airtest.readthedocs.io/zh_CN/latest/all_module/airtest.core.android.android.html)。 ### ADB指令调用 在`Android`设备的测试脚本中,有时候我们需要输入一些`ADB`指令,如果在普通的`Python`脚本中想要调用`ADB`指令,也许需要用到`subprocess`等模块才能运行指令。 但是在`Airtest Project`的脚本中,调用`ADB`指令是非常简单的事情: ```python # 对当前设备执行指令 adb shell ls print(shell("ls")) # 对特定设备执行adb指令 dev = connect_device("Android:///device1") dev.shell("ls") # 切换到某台设备,执行adb指令 set_current(0) shell("ls") ``` ## 3. 测试Android原生应用 poco支持直接对任何**Android原生应用**(非游戏引擎、非webview)进行UI层次结构识别,用法上与poco在其他平台上一模一样。 基于webview的应用比较特殊(如微信小程序或浏览器),请见[webview应用使用poco指引]() ### 准备 在AirtestIDE的`Poco Assistant`面板中选择Android模式,此时会自动向手机里安装 PocoService.apk,以及对应的test apk,并自动启动PocoService,这个是用来自动抓取 Android上界面层次结构的Service,稍等片刻就可以在AirtestIDE界面中看到UI层次结构。 点击任意节点可以`Log`面板中看到其所有属性并在设备画面中框出对应位置。 以上即准备好了Android原生应用测试的开发环境,跟着下面的例子即可开始一个最简单的测试。 ### 例子 点这里下载[示例App(calculator)](http://top.gdl.netease.com/poco-res/poco-demo-android-native-app.zip),并事先将此App安装到手机上。 **首先**必须初始化`poco`实例,才能使用`poco`实例的方法进行对象选择和操作。 下面的例子演示最简单的功能,点击calculator的界面,实现一个`1+1=2`的运算验证。 这只是一个简单的例子,更多的poco用法和例子请见[poco tutorial](http://poco.readthedocs.io/en/latest/source/doc/poco-example/index.html) ```python from poco.drivers.android.uiautomation import AndroidUiautomationPoco poco = AndroidUiautomationPoco() poco('com.google.android.calculator:id/digit_1').click() poco('com.google.android.calculator:id/op_add').click() poco('com.google.android.calculator:id/digit_1').click() poco('com.google.android.calculator:id/eq').click() result = poco('com.google.android.calculator:id/formula').get_text() self.assertEqual(result, '2', '1+1=2 ^^') ``` 如果连接了多个Android设备,则初始化时需要手动指定设备,不然无法识别需要控制哪一台。 使用[airtest.core.api.connect_device](https://airtest.readthedocs.io/en/latest/all_module/airtest.core.api.html#airtest.core.api.connect_device) 连接指定设备,示例见上一章节。 使用`connect_device`连接好指定设备后,会返回一个`Device`对象,将这个对象传入 `AndroidUiautomationPoco`第一个参数里进行`poco`的初始化,接下来使用此`poco` 实例将会获取所指定的设备的UI和对其进行操作。 ```python from airtest.core.api import connect_device from poco.drivers.android.uiautomation import AndroidUiautomationPoco dev = connect_device('Android://:/') poco = AndroidUiautomationPoco(dev) # ... ``` ### 注意事项 需要**Android SDK API version ≥ 19**,即Android 4.4及以上,越高版本兼容性越好。 在Android原生应用上使用poco不需要配置任何依赖,只需手机处于usb调试模式即可(部分手机需要连同usb安装、usb模拟点击等权限一起打开,均位于开发者选项里)。在初始化poco 实例时,会自动向手机里安装PocoService.apk,如果此时弹出安装提示,请点击同意,否则poco无法使用,一共会安装两个app进去。 如果PocoService已经装进去了并且看到了"poco service is running!"的toast,但是仍然无法运行,那可能是还需要打开额外的手机权限,看下手机里有没有其余的权限设置,参考 [文档](../2_device_connection/2_android_faq.html#id7)。 ## 4. API指引 * 设备操作相关:[airtest core API](https://airtest.readthedocs.io/en/latest/all_module/airtest.core.api.html) * 图像识别相关:[airtest doc](https://airtest.readthedocs.io/en/latest/index.html) * UI选择与操作:[poco doc](http://poco.readthedocs.io)