UI自动化测试的价值
1、提升回归测试的效率
2、可以进行兼容性测试
UI 自动化测试应用场景
• 冒烟测试自动化:提测之前自动断言提测质量,提供准入参考。
• 功能测试自动化:辅助 QA 与测试工程师的快速验证。
• 验收测试自动化:兼容性测试等。
• 移动端性能专项测试自动化:性能、卡顿、健壮性测试、竞品分析。
测试框架
• 阿里 Macaca
• 腾讯开源微信小程序自动化测试工具
• 百度内部的 Cafe 框架
自动化测试常见误区
强调自动化测试不代表手工测试无用
• 手工测试非常有用,仅有手工测试是不够的。
• 手工测试 + 自动化测试才是企业快速迭代的根基
UI 自动化测试的“瓶颈”
• 技术成本高:
• 人力成本高:优秀测试开发工程师难招
• 技术门槛高:80%的自动化测试工程师在自动化能力上都不及格
• 维护成本高
• 复用率不高:UI 和业务流程变更是最主要变更
• 稳定性不足:容易被干扰,执行慢
• 常见行业错误观点
• 错误观点一:UI 自动化测试无用论
• 错误观点二:UI 自动化测试只能模拟人工
合理地使用 UI 自动化
• 使用分层测试策略,控制 UI 自动化测试规模:
• 少数核心用例交给自动化测试
• 大部分的基础回归测试交给自动遍历
• 新功能测试交给人工测试
• 技术改进方案:
• 良好的维护模型:PageObject、数据驱动
• 更好的框架支持:增加 Watch,智能等待,失败重试等机制
自动化测试就是机器点点点?
• 传统自动化测试
• 自动探索测试 自动化对新功能进行测试?
• codeless 方向的自动化测试 不需要写代码就可以完成自动化测试
• 自动化测试用例智能生成
如何高效实用的落地自动化
• 学习方向
• 了解待测产品和平台:Android、iOS、App
• 精通最好的测试框架:Appium、UI Automator、WebDriverAgent
• 掌握自动化测试落地经验:PageObject、稳定性提升、数据驱动……
• 达到的结果
• 一天搞定一款 app 的自动化测试脚手架
• 一天完成单个功能的业务测试自动化用例集合
• N 周内搞定公司的 app 自动化测试
移动自动化测试的技术体系
UI 自动化分类
• Web 自动化:Selenium
• App 自动化:Appium
• GUI 自动化:Windows、Mac
• 微信小程序自动化:App + Web 测试技术的外延形态
• 更多平台:智能设备、机器人、工业 app
UI 自动化测试方面的成就
• Google:Espresso、UI Automator
• Facebook:WebDriverAgent
• 焰焮ibaba:Macaca
• Ebay:Selendroid
• Walmart:Robotium
• Sauce Labs:Appium
• ThoughtWorks:Selenium
Appium
Appium 的设计理念
Appium client:对应语言的client包和脚本,如python的Appium-Python-Client并编写脚本
Appium server:启动服务开放端口,接收appium client客户端的http请求
driver:appium需要driver来驱动移动端,Appium team目前维护了很多driver,需要根据平台来选择driver。Android平台一般使用Uiautomator2 driver。。IOS使用XCUITest driver
自动化测试框架选择
• 推荐 Appium
• 跨语言:Java、Python、Node.js 等
• 跨平台:Andoid、iOS、Windows、Mac
• 底层多引擎可切换
• 生态丰富,社区强大
• iOS:KIF、WDA、XCTest
• Android:Robotium、UI Automator
• 特色框架:calabash、Macaca、ATX
Appium 引擎列表
• Android
• Selendroid、Espresso [推荐]
• UI Automator、UI Automator2 [推荐]
• iOS
• UI Automation [已废弃]
• XCUITest [推荐]
• 更多平台:Mac、Windows、游戏引擎等
Appium 多端架构与自动化
UI 分层测试体系
移动 App 分层测试
移动 App 快速迭代模型
自动遍历测试与其价值
• 定义:以自动化的方式对 app 进行充分的功能遍历以探索 bug
• 价值
• 降低自动化维护成本,可替代 80% 的自动化测试
• 实现新功能的探索
• 实现老功能的回归
• 用途:多设备兼容测试、自动化专项测试
常见遍历工具与技术
• Android 原生 Monkey
• 百度 SmartMonkey
• 腾讯 New Monkey
• 阿里 Macaca 的 NoSmoke
• TesterHome 社区 vigossjjj smart_monkey
• TesterHome 社区 zhangzhao Maxim
• TesterHome 社区 seveniruby AppCrawler
• Google 出品的 App Crawler
合理的使用 UI 自动化
• 单元测试:使用 App 分层测试策略,增加单测规模,控制 UI 自动化测试规模。
• 移动 App 自动化测试:核心集成与验收测试用例交给自动化测试。
• 自动遍历测试:大部分的基础回归测试交给自动遍历。
• 人工测试:测试团队主负责,整个产品团队参与。
Android app 的常见概念
Android 自动化前提依赖
• Android SDK:Android Studio 可辅助安装
• 模拟器
• Android Studio 自带 Emulator [推荐]
• Genymotion、网易 MuMu、BlueStacks
• 真机
获取 App 的信息
• App 信息
• 获取当前界面元素:adb shell dumpsys activity top
• 获取任务列表:adb shell dumpsys activity activities
• App 入口
• adb logcat |grep -i displayed
adb logcat | findstr Displayed (windows cmd用这个)
• aapt dump badging mobike.apk | grep launchable-activity
• apkanalyzer 最新版本的 SDK 中才有
• 启动应用
Android 调试桥 adb 命令详解
环境准备
• 真机 or 模拟器
• 下载 Android SDK
• 设置 PATH 变量加入 SDK 的工具目录
Android 常用命令
• adb:Android Debug Bridge
• adb devices:查看设备
• adb kill-server:关闭 adb 的后台进程
• adb tcpip:让 Android 脱离 USB 线的 TCP 连接方式
• adb connect:连接开启了 TCP 连接方式的手机
• adb logcat:Android 日志查看
• adb bugreport:收集日志数据,用于后续的分析,比如耗电量
adb shell
• adb shell 本身就是一个 Linux 的 shell,可以调用 Android 内置命令
• adb shell
• adb shell dumpsys
• adb shell pm
adb shell pm clear com.android.contacts
清除包的缓存数据和权限,获得一个比较新的环境。
• adb shell am
• adb shell am start -W -n com.android.contacts/.activities.PeopleActivity -S
• adb shell ps
• adb shell monkey
常用命令列表
• adb
• pm 包管理工具
• am 启动一个APP
• dumpsys 获取整个系统的性能数据
• uiautomator 获取APP的界面结构,执行自动化测试
• input 完成简单的自动化指令
Android 性能统计 dumpsys
• 获取所有的 dumpsys 子命令 dumpsys | grep -i DUMP
• 获取当前 activity adb shell dumpsys activity top
• 获取 activities 的记录,可以获取到 appium 依赖的原始 activity dumpsys activity activities
• 获取特定包基本信息 adb shell dumpsys package com.xueqiu.android
• 获取系统通知 adb shell dumpsys notification
• 获得内存信息 adb shell dumpsys meminfo com.android.settings
• 获取 cpu 信息 adb shell dumpsys cpuinfo
• 获取 gpu 绘制分析 adb shell dumpsys gfxinfo com.android.settings
• 获取短信 adb shell dumpsys activity broadcasts | grep senderName=
uiautomator
• adb shell uiautomator runtest ...
运行自动化测试用例
• adb shell uiautomator dump
adb shell uiautomator dump
把Android APP控件生成xml文件
UiAutomator是测试Android原生态APP的功能测试工具。Android 4.1发布时包含了这种新的测试工具—UiAutomator。UiAutomator用来做UI功能测试的。
uiautomator2是uiautomator的升级版,uiautomator是Google开发的一款用来做安卓自动化测试的Java库。适用于Android4.4+
简单的自动化工具 input 命令
• text (Default: touchscreen)
• keyevent [--longpress] ... (Default: keyboard)
• tap (Default: touchscreen)
adb shell input tap 529 1176
点击屏幕上该坐标
• swipe [duration(ms)] (Default: touchscreen)
• draganddrop [duration(ms)] (Default: touchscreen)
• press (Default: trackball)
• roll (Default: trackbal
Appium 架构介绍
文档:The Context API - Appium Documentation
Appium 生态工具
• adb:Android 的控制工具,用于获取 Android 的各种数据和控制
• Appium Desktop:内嵌了 Appium Server 和 Inspector 的综合工具
• Appium Server:Appium 的核心工具,命令行工具
• Appium Clients:各种语言的客户端封装库,用于连接 appium server
• Java、Python、Ruby、robotframework-appium
• AppCrawler 自动遍历工具
Desktop 主要功能
• UI 分析
• 录制用例
• 元素查找测试
• Attach 已有的 session
• 云测试
python 客户端安装
• 客户端安装:pip install Appium-Python-Client
• IDE:PyCharm
• Python 多版本隔离工具:venv
• 国内依赖源:http://pypi.douban.com/simple/
• 测试框架:unittest、pytest、nose,推荐 pytest
APP自动化
控件定位方法
常用定位手段
• id
• Accessibility ID
• XPath
元素定位
• 测试步骤三要素:
• 定位、交互、断言
• 定位
• ID (重要)
• XPath(重要)
• Accessibility ID: content-desc(重要)
• 不推荐:Class -iOS -Android
常用自动化 API
常见自动化动作支持
• click
• sendKeys
• swipe
• touch action
手势操作 TouchAction
• press release longPress
• tap wait
• moveTo
• perform
capabilities 设置
Capabilities - Appium Documentation
Capabilities是appium启动server会话时设置的参数,告诉server需要启动的APP入口,android版本等信息。
• App APK 地址 appPackage 包名 appActivity Activity 名字
• automationName 默认使⽤ uiautomator2
• noReset fullReset 是否在测试前后重置相关环境
• autoGrantPermissions ⾃动赋予 App 权限
• unicodeKeyBoard resetKeyBoard 是否需要输⼊⾮英⽂之外的语⾔并在测试完成后重置输⼊法
Appium 设备交互 API
可见Appium Python Client 文档Welcome to Appium python client’s documentation! — Python client 1.0 1.0 documentation
常用的设备交付命令
• 模拟电话、短信
用下面的命令模拟 GSM 电话和短信,注意:只能在模拟器上使用!
self.driver.make_gsm_call("5551234567", GsmCallActions.CALL);
self.driver.send_sms('555-123-4567', 'Hey lol')
Original error: gsmCall method is only available for emulators 这里在夜神模拟器上执行是失败的。
• 横竖屏切换
• App 处理
# 实现 APP 的安装
self.driver.install_app('/Users/johndoe/path/to/app.apk')
# 检测 APP 是否被安装
self.driver.is_app_installed('com.example.AppName');
# 启动 APP
self.driver.launch_app()
• 键盘、粘贴板
设置系统剪贴板的内容:
self.driver.set_clipboard('happy testing')
self.driver.set_clipboard_text('happy testing')
获取到剪贴板的内容:self.driver.get_clipboard()
self.driver.get_clipboard_text()
• 录屏
显式等待
• 功能差别
• 显式等待的条件非常灵活
• 隐式等待只用于元素定位
• 执行差别
• 显式等待本地轮询条件
• 隐式等待通过 appium server 轮询条件
def assert_exist_element(self,loc): try: WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located(loc)) return True except: print("元素{}不存在".format(loc)) return False
XPath 介绍
• 绝对定位:根据严格的父子关系定位
• 相对定位:根据条件匹配定位
• 慢的原因:XPath 定位比其他定位慢,因为需要递归解析每个元素的属性
• 慢的不明显的原因:有 Cache 机制
常用 XPath 相对定位表达式
• 查找:
• //*[@text='登录’]
• //*[contains(@resource-id, 'login’)]
• 条件匹配:
• //*[contains(@resource-id, ‘login’) and contains(@text, ‘登录’)]]
• //*[contains(@text, ‘登录’) or contains(@label, '登录’)]]
• 寻找所有元素://*
Toast 识别方法
• automationName:uiautomator2
• getPageSource 是无法找到的
• 必须使用 xpath 查找
• 推荐 //*[@class= ‘android.widget.Toast']
• 或者 //*[contains(@text, "xxxxx")]
断言体系
元素是否存在:find_elements
assert len(self.driver.find_elements(by=AppiumBy.XPATH, value='//*[@text="Battery"]'))>=1 #断言存在该元素 assert "哈哈" in self.driver.find_element(by=AppiumBy.XPATH, value='//*[@text="Battery"]').text
• 元素属性正确性:get_attribute
xUint常用断言
传统的xUnit风格的assertXXX()系列
Hamcrest断言,基于更灵活的Matchers断言方式 --推荐 https://github.com/hamcrest/PyHamcrest
参数化与数据驱动
参数化
• 参数化:根据传入的数据,对测试用例进行迭代调用 如pytest的pytest.mark.parametrize
• 数据驱动:基于数据完成流程调度,通常数据来源自外部数据文件
• 参数化是数据驱动的基础和特例
数据驱动
• 参数化数据读取自外部文件:使用 YAML、JSON 读取
• 测试步骤读取自外部文件:定制执行引擎
• 断言步骤读取自外部文件:定制执行引擎
• 整个用例读取自外部文件:动态创建用例
APP分类
Native 原生 App 的自动化测试
多种架构支持
Native 原生应用的分类
• Android 标准组件
Activity组件、service组件、content provider组件、broadcase receiver组件
• 非标准组件:
-Flutter:闲鱼
-React Native:Facebook
- Weex:极客时间
也可以使用appium进行测试
• 游戏
非标准组件APP的特征
如极客时间APP,非标准控件会被解析
• 不是WebView 组件
• 原生控件可识别,非原生的被解析
• HTML 控件被编译为 Native 控件如view
• HTML 的文本属性被解析为 Native 属性
• text 还是 content-desc 取决于 API 版本
常见 Native 自动化测试方式
• Android 原生组件:Appium 默认支持
• Native非标准组件:Appium默认支持
• 自定义 View 识别:
1)使用相对定位,父控件加百分比偏移
2)OCR、图像识别、AI
• 游戏控件识别:使用游戏引擎特定技术
游戏自动化测试支持
• Appium 提供了简单的游戏自动化测试支持
•1)图像识别
•2)AI 识别
•游戏测试的推荐做法
1)提高可测性:编码输出游戏引擎下的控件布局信息,与 Appium 对接
2) 使用成熟的 airtest 框架
Hybrid 混合 App 的自动化测试
WebView 控件在 Appium 中的抽象
• Native 层面支持
1) uiautomator 解析 WebView 中的内容并映射为原生控件
•2)getPageSource 为 DOM 结构可发现 WebView 组件和控件
• 切换为 WebView 上下文
1)切换后才是正规的 Web
2)getPageSource 为 HTML
3)可以使用 CSS 定位等
Hybrid 测试流程
• 首先进去带有 WebView 的页面
• 使用 Contexts API 寻找 WebView
• 使用 Context 切换到 WebView
• 使用 CSS 等 Web 定位方式
• 使用 Context 重回 Native
真机进行 WebView 测试的前提
• 模拟器默认支持解析webview控件
• 物理机需要打开 app 内开关(需要开发人员修改配置)
• 检测是否打开:反编译检查对应的 API 调用
WebView 测试 - Python
找对 ChromeDriver 的版本
• Android 默认浏览器:
• 老版本 Android 用 Browser,新版本 Android 用 Chrome
• adb shell dumpsys package com.android.webview | grep versionName
• adb shell dumpsys package com.android.chrome | grep versionName
• App 自带 WebView 组件:每个 App 自带的 WebView 的版本也都不相同
Android WebView进程信息
• getContextHandles
• 查看所有的 WebView 进程
• adb shell cat /proc/net/unix | grep webview
• Context 切换
• 把 domain socket 映射为本地的 socket 端口
• adb forward tcp:$port localabstract:webview_devtools_remote_$pid
• 获取对应的 WebView 组件版本 http://localhost:$port/json/version
• ChromeDriver 协议交互
设置 ChromeDriver
• ChromeDriver 安装
• 提前下载所有的 ChromeDriver 版本备用
• 运行时指定
• 隐式选择:1.8版本以后支持自动选择 ChromeDriver
• 显式指定:chromedriverExecutableDir 设置
• 调试开关:
• showChromedriverLog
纯 H5 站自动化测试
浏览器自动化技术原理
浏览器调试工具 DevTools
对网站进行分析
移动浏览器测试 - Python
小程序自动化测试
小程序自动化的三个方法
• 利用 Uiautomator 的原生定位
• 利用微信提供的小程序自动化 SDK
• 基于WebView的测试方法
基于原生定位的方法
• Appium 使用 Uiautomator2 定位可以识别内部 WebView 组件
• 缺点:元素定位符不够精确,content-desc、resource-id 多数都没有
• NoReset 默认为 false,会默认清空微信聊天记录,所以请使用测试机测试帐号
基于微信提供的小程序自动化 SDK
• 使用 Node.js 体系
• 微信小程序自动化 SDK + 标准的测试框架
• 支持真机与 Web 模拟器
微信小程序自动化 SDK 的缺点
• 从官网提供的代码示例来看,微信的这套体系主要用于研发自测
• 微信的研发对自动化测试理解不到位,大量的 wait,实用性不高
• 需要在已有的 WebSocket 体系上做二次封装对接 Appium
• 希望微信可以重视这块的测试支持改进
基于 WebView 的测试方法
• 微信6.x版本支持基于 WebView 自动化测试
• 7.x改版后默认已经无法使用基于 WebView 的自动化
• 7.x + root强行开启 WebView debug + Appium hack
• 曾经这个方案是最好用的,Appium 默认支持
• 但是当前微信版本里这个方法已经被破坏,绕过条件比较苛刻,暂时不可用了
iOS 测试工具体系
主流移动测试框架
• Appium
• Calabash iOS
• KIF
• XCTest
• WebDriverAgent
• UIAutomation(在 Xcode8 后废弃)
基础工具
• Xcode Xcode 是苹果公司向开发人员提供的集成开发环境(非开源),用于开发 Mac OS X 的应用程序。
Xcode
• 演练 example:https://github.com/appium/ios-uicatalog
• Xcode 编译
• 观察 build 过程提取编译文件
• 导出文件和 dSYM 文件
• xcodebuild xcodebuild是一个命令行工具,允许你从命令行对Xcode项目和工作区执行编译、查询、分析、测试和归档操作。它对项目中包含的一个或多个目标或项目或工作区中包含的方案进行操作
• instruments工具包-专项工具包
• libimobiledevice libimobiledevice又称libiphone,是一个开源包,可以让Linux支持连接iPhone/iPod Touch等iOS设备
常用测试辅助工具
• 依赖工具包安装:
• brew install --HEAD ideviceinstaller
• brew install --HEAD libimobiledevice
• brew install ios-deploy
• 查看模拟器列表:instruments -s devices
查看真机列表:idevice_id -l
• 安装 app: ideviceinstaller -i demo.app 高版本使用:ios-deploy
• 命令行编译:
• xcodebuild -scheme UICatalog -target iOS clean build
• xcodebuild -scheme UICatalog -target iOS archive
WDA 与 Appium 的关系
• WDA 本身也是一个完整的基于 WebDriver 协议的框架
• Appium 使用 WDA 作为底层的 iOS 自动化框架
iOS 模拟器自动化测试
常用控件定位方式
• name:ID 定位
• label:AccessibilityID 定位
• value:XPath 定位
用例演练
• 打开 UiCatalog
• 点击 Buttons
• 断言是否存在“More Info”按钮
Page Object 模式
做法
• 以页面为单位独立建模
• 隐藏实现细节
• 本质是面向接口编程
• 优点
• 减少重复 find click 样板代码
• 易读性提高
• 页面修改不影响测试用例
Page Object 六大设计原则
方法意义
• 用公共方法代表 UI 所提供的功能
• 方法应该返回其他的 Page Object 或者返回用于断言的数据
• 同样的行为不同的结果可以建模为不同的方法
• 不要在方法内加断言
字段意义
• 不要暴露页面内部的元素给外部
• 不需要建模 UI 内的所有元素
登录场景
• 登陆页面提供 login findPassword 功能
• Login 类 + login findPassword 方法
• 登录页面内的元素有多少并不关心,隐藏内部界面控件
• 登录成功和失败会分别返回不同的页面
• findPassword
• loginSuccess
• loginFail
• 通过方法返回值判断登录是否符合预期
编写用例顺序
• 编写用例
• 实现 page页面和 方法
• 调试使测试用例运行通过
整体类似TDD风格
BasePage 封装
• 实现通用的 Page 方法,对常用自动化行为做封装,其他页面都需要继承basepage
• 管理各种 Driver
• 减少每个 Page 对 Appium、Selenium 等库的太多依赖
自动化行为封装
• 异常弹框处理:广告、好评、升级、tips 等弹框
• 通用自动化能力封装
Java Python的封装方式
• Java:
• Page Factory + @FindBy
• Python:
• PyDOM、独立封装 如poium
基于 POM 的用例组织结构
• page目录:完成对页面的封装
driver声明为WebDriver类型,可以在该类中调用driver的方法。
class MainPage(BasePage):
_search_locator = (By.ID, "com.xueqiu.android:id/home_search")
def to_search(self):
#todo: too slow
self.find_element_and_click(self._search_locator)
return SearchPage(self.driver)
MainPage中点击一个按钮进入另一个Page,所以返回searchPage
• driver:完成对 Web、Android、iOS、接口的驱动
• testcase目录:存放test_XX.py文件 调用各类 page 完成业务流程并进行断言
• data:配置文件和数据驱动
• utils:其他便捷的功能封装,可选
源码:2504973175/Geek_AppAutomationTestingCode (gitee.com)
测试用例管理
• 用例组织结构:
• 使用 package 管理业务模块
• 使用 class 管理业务对象、使用method完成业务具体行为
• 数据驱动:测试数据、测试步骤、测试断言
• 测试用例:
• 使用 testcase 完成测试步骤的定义
• 使用 assertion 完成业务正确性校验
• 持续集成:使用 Jenkins 完成持续集成
Appium 错误排查与日志分析
appium -g <log file path>
• shell 命令
• WebDriver 请求
• ChromeDriver 日志
调试分析方法
• Appium Log
清晰记录了所有的请求和结果以及底层的一些错误堆栈
• 分析界面数据
使用 getPageSource 获取界面的完整 DOM 结构
利用 XPath 获取所有匹配的元素
• 脚本外调试
借助于 curl 命令从脚本外探测界面数据
adb 知识与排错
adb 排错
• adb client:普通的 adb 命令,使用 shell 脚本代替
• adb server:
• pc 上的一直开启的 server 进程
• adb 命令通过 adb 协议与 adb server 通讯
• 通过代理转发结合 capability
Appium 原理与 JSONWP 协议分析
WebDriver 协议与手工模拟
• WebDriver 协议基础知识要懂
• session_id 获取
• session_id= ` curl http://127.0.0.1:4723/wd/hub/sessions | awk -F\" '{print $8}' `
• element id 获取
• curl -X POST http://127.0.0.1:4723/wd/hub/session/$session_id/elements --data-binary '{"using":"xpath" , "value":"//*[@class=\"android.widget.Toast\"]"}' -H "Content-Type: application/ json;charset=UTF-8"
• 元素属性获取
• curl http://127.0.0.1:4723/wd/hub/session/$session_id/element/$element_id/attribute/text
• 元素动作
• curl -X POST http://127.0.0.1:4723/wd/hub/session/$session_id/element/$element_id/click
Appium 源码分析
所有源代码
• appium server
• Node.js 系列包
• adb shell
• ChromeDriver
• 底层引擎
• Uiautomator Java
• WDA
• selenium
• appium client:Python、Java
Appium 二次封装
自定义 Appium Server
• git clone
• npm install
重新编译 Uiautomator
• git clone
• Gradle