1、APP测试的时代背景
我们面临的问题
- 按月发布->按周发布->按小时发布
- 多端发布:Android、iOS、微信小程序、h5
- 多环境发布:联调环境、测试环境、预发布环境、线上环境
- 多机型发布:众多设备型号、众多系统版本
- 多版本共存:用户群体中存在多个不同的版本
- 历史回归测试任务:成百上千条业务用例如何回归
- 总结:加班+背锅
2、Appium介绍
- 推荐Appium
- 跨语言:Java、Python、nodejs等
- 跨平台
- Andoid、iOS
- Windows、Mac
- 底层多引擎可切换
- 生态丰富,社区强大
Appium框架结构
- node.js:appium的运行环境
- appium desktop:集成了node.js和appium
- appium server:包含各种工作引擎,根据平台进行切换。是第一个收集日志的位置。
Appium引擎列表
- Android
- espresso
- selendroid
- uiautomator
- uiautomator2[推荐]
- iOS
- uiautomation
- xcuitest [推荐]
- mac
- windows
3、Appium环境安装
- Appium环境参照前面文章
- sdk 环境:
安装JDK
需要安装1.8版本的JDK,Linux系统通过apt/yum安装openjdk即可,Mac可以通过brew安装,win10的话,可以从学院提供的百度网盘中下载小于200版本的JDK1.8,因为达到200版本在WIn10安装的时候会有闪退的问题
安装过程全程默认即可,不需要更改
-
安装完毕后需要配置环境变量:首先是JAVA_HOME,是一个独立的环境变量
还有path环境变量中需要配置几项:
%JAVA_HOME%
%JAVA_HOME%\bin
%JAVA_HOME%\jre\bin
安装Android Studio
- 官网下载地址
- 通过官网下载Android Studio对应版本后,直接安装即可
初始化Android环境、安装SDK
- 安装Android Studio之后初次启动的时候会需要进行环境的初始化,安装的时候使用标准安装即可。现在国内可以正常访问dl.google.com这个域名了,所以不用配置特殊手段也可以正常安装SDK等内容
SDK默认需要安装的部分
-
在AndroidStudio欢迎界面打开SDKmanager,在SDK Tools目录下按照如下选择进行安装,注意其中的Build-Tools部分参考最下方的GIF
配置环境变量
Windows
- 在系统变量中新建一个变量,名字为
ANDROID_HOME
,值为电脑SDK的根目录,一般默认安装的路径为C:\Users\用户名\AppData\Local\Android\Sdk
(用户名为你电脑登录用户的用户名),可以去自己的文件夹下查看具体路径,不要写错 - 修改系统变量中的path变量,添加四条内容,因为可能会有其他软件也带有adb执行文件,未免出现问题,尽量将这四项配置到较靠前的位置
%ANDROID_HOME%\emulator
%ANDROID_HOME%\tools
%ANDROID_HOME%\tools\bin
%ANDROID_HOME%\platform-tools
Linux/Mac
- 在环境变量中配置
ANDROID_HOME
变量,值为SDK的根目录,之后将四个文件夹配置到path变量中,并使用source命令或者重启让配置生效
$ANDROID_HOME/emulator
$ANDROID_HOME/platform-tools
$ANDROID_HOME/tools
$ANDROID_HOME/tools/bin
确认配置是否生效
- 在命令行执行
adb version
,确认没有报错,提示的adb位置是之前所安装的sdk目录下 - 在命令行执行
emulator -version
,确认没有报错,并且显示了Android emulator version信息
修改build-tools版本
-
由于默认会安装最新版本的bulid-tools,但是30版本开始build-tools配合jdk1.8会报错,所以需要手动降级到29版本,具体降级方法见下图
注意
- Appium建议1.5
- Java 1.8
- SDK build-tools/下对应的版本,需要使用<=29的版本
4、Android自动化前提依赖
- Appium Desktop:入门学习工具
- 设备:模拟器或真机
- 网易mumu、夜神、雷电、逍遥
- Android Studio自带emulator[推荐]
- Genymotion(Windows上不建议)
- 真机:
- 安装驱动(手机助手、豌豆荚等)
- 开发者选项-开启调试模式
- Android SDK
- 连接mumu模拟器
- 【win版】
adb connect 127.0.0.1:7555
adb shell
- 【mac版】
adb kill-server && adb server && adb shell
- 【win版】
- 下载app使用应用宝等平台
- 命令行安装:
adb install path/*.apk
- 命令行卸载:
adb uninstall 包名
- 在python中安装依赖包:
pip install appium-python-client
获取App信息
- app入口,两种方式获取
- 1、通过logcat日志获取
- mac/ Linux:
adb logcat | grep -i ActivityManager
- windows:
adb logcat | findstr -i ActivityManager
- 获取当前页的activity:
adb shell dumpsys window | grep mCurrentFocus
,所以最好使用上面的方法获取app的启动页
- mac/ Linux:
- 2、通过aapt获取
aapt dump badging wework.apk | grep launchable-activity
- 1、通过logcat日志获取
- 启动应用
adb shell am start -W -n <package-name>/<activity-name> -S
5、appium建立连接的python脚本
from appium import webdriver
caps = {}
caps ["platformName"] = "Android"
caps ["deviceName"] = "insane"
caps ["appPackage"] = "com.tencent.wework"
caps ["appActivity"] = ".launch.LaunchSplashActivity"
caps ["noReset"] = "True"
driver = webdriver.Remote("http://localhost:4723/wd/hub",caps)
-
driver = webdriver.Remote("http://localhost:4723/wd/hub",caps)
是建立客户端与服务端连接的重要代码
6、元素定位
- 测试步骤三要素:
- 定位、交互、断言
- 定位
- Id定位(优先级最高)
- XPath定位(速度慢,定位灵活)
- Accessibility ID定位(content-desc)
- Uiautomator定位(速度快,语法复杂)
XPath定位
- 绝对定位:不推荐
- 相对定位:
//*
-
//*[contains(@resource-id, 'login')](重点)//*[@text=‘登录]
(重点) -
//*'contains(@resource-id, 'login') and contains(@text, '登录')]
(重点) -
//*[contains(@text,'登录')or contains(@class, 'EditText')]
(了解) -
//*ends-with(@text,号)] | //*[starts-with(@text,姓名')]
两个定位的集合列表(了解) -
//*(@clickable="true”] // android.widget.TextView[string-length(@text)>0 and string-length(@text)<20]
(了解) -
//*[contains(@text,"看点')/ancestor::*//*[contains(@class, 'EditText')]
(轴)(了解)
原生定位
- 官网:https://developer.android.com/reference/android/support/test/uiautomator/UiSelector.html
- Uiautomator定位
- 写法:
new UiSelector().text("text")
- 写法:
- 滚动查找:
- 写法:
'new UiScrollable(new UiSelector()' '.scrollable(true).instance(0))' '.scrollIntoView(new UiSelector()' '.text("目标文本").instance(0));'
- 写法:
Toast定位
- appium使用uiautomator底层的机制来分析抓取toast,并且把toast放到控件树里面,但本身并不属于控件。
- automationName: uiautomator2
- getPageSource是无法找到的
- 必须使用xpath查找
//*[@class='android.widget. Toast']
//*[contains(@text, "xxxxx")]
7、实战代码
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from time import sleep
from appium import webdriver
from appium.webdriver.common.mobileby import MobileBy
class TestWX:
def setup(self):
caps = {}
caps ["platformName"] = "Android"
caps ["deviceName"] = "insane"
caps ["appPackage"] = "com.tencent.wework"
caps ["appActivity"] = ".launch.LaunchSplashActivity"
caps ["noReset"] = "True"
self.driver = webdriver.Remote("http://localhost:4723/wd/hub",caps)
self.driver.implicitly_wait(5)
def teardown(self):
self.driver.quit()
def test_contact(self):
name = "insane"
gender = '男'
phone = '12312312312'
# 点击【通讯录】
self.driver.find_element(MobileBy.XPATH, "//*[@text='通讯录']").click()
# 滚动查找【添加成员】
self.driver.find_element(MobileBy.ANDROID_UIAUTOMATOR,
'new UiScrollable(new UiSelector()'
'.scrollable(true).instance(0))'
'.scrollIntoView(new UiSelector()'
'.text("添加成员").instance(0));')
# 点击【手动输入添加】
self.driver.find_element(MobileBy.XPATH, "//*[@text='手动输入添加']").click()
# 输入姓名
self.driver.find_element(MobileBy.XPATH, "//*[contains(@text,'姓名')]/../*[text='必填']").send_keys(name)
# 选择性别
self.driver.find_element(MobileBy.XPATH, "//*[@text='性别']/..//*[@text='男']").click()
if gender == '男':
self.driver.find_element(MobileBy.XPATH, "//*[@text='男']").click()
elif gender == '女':
self.driver.find_element(MobileBy.XPATH, "//*[@text='女']").click()
# 输入手机号
self.driver.find_element(MobileBy.XPATH, "//*[@text='手机号']").send_keys(phone)
self.driver.find_element(MobileBy.XPATH, "//*[@text='保存']").click()
result = self.driver.find_element(MobileBy.XPATH, "//*[@class='android.widget.Toast']").text
assert result == "添加成功"
# sleep(2)
# print(self.driver.page_source)