软件测试所有内容笔记正在陆续更新中,笔记已经在本地记录,全部为自己手动记录的笔记及总结,正在开始更新中,后续会逐步更新并完善到 软件测试学习内容总结
专栏。
本节内容:移动端app自动化测试
1. appium环境安装与架构介绍
1.1 目前mobile自动化解决方案
自动化工具选择
- 单平台测试 or 多平台测试?
- 是否有多设备同时测试的场景?
- 不局限于测试环境,任何版本任何环境都可以测试?
- 最擅长哪种开发语言?
- 当前市面是否有满足项目需求的测试工具?是否需要二次开发?
1.2 appium 介绍
Appium是一个移动端的自动化测试框架
,可用于测试原生应用,移动网页应用和混合应用
,且是跨平台。可用于iOS和Android操作系统。原生应用是指用Android或iOS编写的应用,移动网页应用是指网页应用,类似于iOS中Safari应用或者Chrome应用或者类似浏览器的应用。混合应用是指一种包裹webview的应用,原生应用网页内容交互性的应用。
重要的是Appium是跨平台的。何为跨平台,意思是可以针对不同平台用一套api来表写脚本。
原生应用 – 手机设置,
移动网页应用 – 手机浏览器打开的应用,
混合应用 – 原生应用嵌套了网页应用,微信小程序
推荐Appium
- 跨语言:Java、Python、nodejs等
- 跨平台
- 底层多引擎可切换
- 生态丰富、社区强大
Appium工作引擎
对于Android、iOS底层使用了不同的工作引擎驱动实现自动化测试。Appium引擎列表:
Appium的设计理念
- webdriver是基于http协议的,第一连接会建立一个session会话,并通过post发送一个json告知服务端相关测试信息
- Client/Server设计模式
- 客户端通过WebDriver json wire协议与服务端通讯
- 多语言支持
- Server可以放在任何地方
- 服务端NODEJS开发的HTTP服务
- appium使用appium-xcuitest-driver来测试iPhone设备,其中需要安装Facebook出的WDA(webdriver agent)来驱动iOS测试
入门篇 - appium环境安装
appium生态工具
- adb:Android的控制工具,用于获取Android的各种数据和控制
- Appium Desktop:内嵌了Appium server和inspector的综合工具
- Appium Server:Appium的核心工具,命令行工具
- Appium client:各种语言的客户端封装库,用于连接Appium server
- Python、Java、ruby、robotframework-appium
- AppCrawler:自动化遍历工具 --思寒
Appium安装 - 简化版
环境安装
- Java 1.8版本(配置环境变量)
- Android SDK(配置环境变量)
- Appium Desktop
- Python3
- Appium python client
软件下载地址
JDK安装与配置
SDK安装与配置 - 简化版
SDK安装与配置 - 进阶版
Appium Desktop 安装与配置
- 安装appium desktop(appium server + appium inspector工具)
Appium 客户端安装与配置
- 安装Python3环境
- <topic/57> 安装Python+pycharm环境帖
- 安装Appium python client两种方式:
- 方式一:
pip install appium-python-client
(推荐)
- 方式二:下载源码包:
运行测试用例
- 验证环境是否成功
- 1、首先打开appium desktop,点击start server(不报错)
- 2、其次准备一个Android设备,真机或者模拟器(推荐mumu模拟器)
- 3、模拟器连接电脑
- 4、adb devices查看设备是否连接
- 5、最后编写测试脚本,运行脚本,不报错
下载安装模拟器
- mumu模拟器
- 电脑开启VT(虚拟化技术)
- 设置屏幕显示(720*1280)重启
- 连接设备adb connect
代码示例
Appium安装 - 服务版
Appium Server环境信赖
- Java1.8版本
- Android sdk
- Node js(>=10版本),npm(>=6版本)(推荐下载Node.js 12.x)(重点)
- Appium Server
- Python3
- Appium python client
Node.js安装
安装 Appium Server
- 如果不需要Appium inspector,也可以通过npm直接安装Appium server
- 官方安装(推荐)
-
npm install -g appium
(-g参数表示全局安装)(不建议这样 安装,这样安装最新版)
-
npm install -g appium@1.91.1
指定版本安装(最新1.21,建议安装低1-2个版本)
- 淘宝提供(不推荐)
- npm install -g cnpm --registry.npm.taobao.org
- cnpm install -g appium
- 运行
-
appium --version
查看版本
-
appium
启动Appium服务(不报错说明安装成功)
Appium Doctor安装
- 安装appium-doctor检测appium的安装环境
npm install -g appium-doctor
- 在命令行执行
appium-doctor
运行测试用例
- 验证环境是否成功
- 1、首先运行appium server(不报错)
- 2、其次准备一个Android设备,真机或者模拟器(推荐mumu模拟器)
- 3、模拟器连接电脑
- 4、adb devices查看设备是否连接
- 5、最后编写测试脚本,运行脚本,不报错
启动appium server
创建文件demo.py,执行python demo.py
from appium import webdriver
desired_caps={}
desired_caps['platformName']='Android'
desired_caps['platformVersion']='6.0'
desired_caps['deviceName']='emulator-5554'
# com.android.settings/com.android.settings.Settings
desired_caps['appPackage']='com.android.settings'
desired_caps['appActivity']='com.android.settings.Settings'
driver=webdriver.Remote('http://localhost:4723/wd/hub',desired_caps)
print("启动【设置】应用")
driver.quit()
1.3 appium 框架介绍
1.4 appium 环境安装
2. appium用例录制
2.1 android自动化前提依赖
Android自动化前提依赖
- adb工具
- 模拟器 or 真机
- 模拟器:网易mumu,genimotion,或者SDK自带的模拟器
- 真机需要root权限
- Appium Desktop:入门学习工具
2.2 appium desktop功能介绍
desktop主要功能
- UI分析
- 录制用例
- 元素查找测试
- Attach已有的session
- 云测试
2.3 利用appium desktop生成用例模板
获取app的信息
- app信息
- 获取当前界面元素:
adb shell dumpsys activity top
(推荐)(重点)
- 获取任务列表:
adb shell dumpsys activity activities
- app入口
-
adb logcat | grep -i displayed
(推荐)(重点)
aapt dump badging mobike.apk | grep launchable-activity
-
apkanalyzer
最新版本的sdk中才有
- 启动应用
-
adb shell am start -W -n com.xueqiu.android/.view/WelcomeActivityAlias -S
(重点)
adb shell dumpsys activity top 查找最上层的activity的展示
adb shell am start -W -n com.xueqiu.android/.main.view.MainActivity
配置待测应用的信息(desire capability)
导出python语言的用例
添加隐式等待增强用例稳定性
配置待测应用
利用Appium Desktop生成用例模板
: start inspector session: get raw logs - 下载日志到本地: stop server
Automatic Server:自动的server
Custom Server:本地的server
Select Cloud Providers:云服务 - 国外
https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/caps.md
{
“platformName”: “android”,
“deviceName”: “mumu”,
“appPackage”: “com.xueqiu.android”,
“appActivity”: “.view.WelcomeActivityAlias”
}
按钮1 - 选择页面元素,会在右边的布局结构中展示元素的位置及层级结构,在最右侧展示出元素的所有的属性
2 - 滑动 通过坐标点进行滑动(给定2个坐标点-鼠标在页面不同位置点击)
3 - 点击 通过坐标点进行点击
4 - 返回
5 - 刷新
6 - 录制脚本
7 - 搜索
8 - 拷贝 拷贝当前xml的结构
9 - 关闭session
el2 = driver.find_element_by_xpath("/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.view.ViewGroup/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.RelativeLayout/android.view.ViewGroup/android.widget.LinearLayout/android.widget.RelativeLayout[1]/android.widget.RelativeLayout/android.widget.ViewFlipper/android.widget.LinearLayout/android.widget.TextView")
el2.click()
el3 = driver.find_element_by_id("com.xueqiu.android:id/search_input_text")
el3.send_keys("alibaba")
el4 = driver.find_element_by_xpath("/hierarchy/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.view.ViewGroup/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.RelativeLayout/android.widget.FrameLayout/android.widget.LinearLayout/androidx.recyclerview.widget.RecyclerView/android.widget.RelativeLayout[1]/android.widget.LinearLayout/android.widget.TextView[1]")
el4.click()
3. 元素定位方法与隐式等待
3.1 desirecapability介绍
测试用例的重要部分
- 导入依赖:
from appium import webdriver
- capabilities 设置
- 初始化driver:
- 隐式等待,增强用例的稳定性
- 元素定位与操作 find+action
- 断言 assert
Capability设置
- app apk地址
- appPackage 包名
- appActivity Activity名字
- automationName 默认使用uiautomator2(android默认使用uiautomator2,iOS默认使用XCUITest)
- noReset fullReset 是否在测试前后重置相关环境(例如首次打开弹框,或者是登录信息)
- 演示雪球的首次启动弹窗功能,noreset = True, noreset = false情况
- unicodeKeyBoard resetKeyBoard 是否需要输入非英文之外的语言并在测试完成后重置输入法
- 官方文档:https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/caps.md
- dontStopAppOnReset 首次启动的时候,不停止app(可以调试或者运行的时候提升运行速度)
- skipDeviceInitialization 跳过安装,权限设置等操作(可以调试或者运行的时候提升运行速度)
3.2 appium元素定位
appium元素定位
- 常用的两种定位方式id,accessibility_id
- driver.find_element_by_id(resource-id)
- driver.find_element_by_accessibility(content-desc)
三种经典等待方式
- 强制等待
- 隐式等待(全局性)
- 设置一个超时时间,服务端appium会在给定的时间内,不停的查找,默认值是0
- 用法:
driver.manage().timeouts().implicitlyWait(10,TimeUnit.SECONDS)
;
- 在服务端等待
- 显示等待(等待某个元素)
Element = WebDriverWait(driver,10,0.5).until(\ expected_conditions.visibility_of_element_located((MobileBy.ID,"com.android.settings:id/title")))
- 在客户端等待
3.3 隐式等待
隐式等待
- 使用方法
- driver.implicitly_wait(time) -全局的等待
实例展示
from appium import webdriver
desired_caps={}
desired_caps['platformName'] = 'Android'
desired_caps[''] = ''
desired_caps['noReset'] = 'true'
driver = webdriver.Remote('http://12.0.0.1:4723/wd/hub', desired_caps)
driver.implicitly_wait(5)
driver.quit()
driver = webdriver.Remote(‘http://12.0.0.1:4723/wd/hub’, desired_caps)
driver.implicitly_wait(5) -全局的等待
4. app控件定位
4.1 android/ios基础知识
Android基础知识
- 布局是一种可用于放置很多控件的容器,它可以按照一定的规律调整内部控件的位置,从而编写出精美的界面。当然,布局的内部除了放置控件外,也可以放置布局,通过多层布局的嵌套,我们就能够完成一些比较复杂的界面。
iOS基础知识
- iOS介绍
- 由苹果公司为iPhone开发的操作系统,主要给iPhone,iTouch,iPad使用
- 原名iPhoneOS,2010年WWDC大户改名为iOS
- 目前iOS最新版本是iOS13
- 布局
- iOS去掉了布局的概念,直接用变量之间的相对关系完成位置的计算
- 开发环境
- 系统:MacOS X
- 开发工具:Xcode
- 开发语言:ObjectC
- 安装文件:.ipa文件 / .app文件
- 注意:
- 使用Appium测试iOS应用需要使用MacOS操作系统
元素定位
- 元素定位,实际上就是定位控件
- 要想一个脚本同时支持android/iOS两个系统,就得保证元素属性(id,aid,xpath)一致
控件基础知识
- dom:Document Object Model 文档对象模型
- dom应用:最早应用于html和js的交互。用于表示界面的控件层级,界面的结构化描述,常见的格式为html、xml。核心元素为节点和属性。
- xpath:xml路径语言,用于xml中的节点定位。
- Android应用的层级结构与html不一样,是一个定制的xml
- app source类似于dom,表示app的层级,代表了界面里面所有的控件树的结构
- 每个控件都有它的属性(resourceid,xpath,aid),没有css属性
4.2 dom结构解读
app dom结构解析
app dom为例
- node
- attribute
- clickable
- content-desc
- resource-id
- text
- bounds
- iOS与Android的区别
- dom属性和节点结构类似
- 名字和属性的命名不同(比如:android resourceid,ios name;android content-des,ios accessibility-id)
4.3 id、aid、xpath定位方法
定位方法
- 测试步骤三要素:
- 定位方法:
- id定位
- driver.find_element_by_id(resource-id属性值)
- driver.find_element(MobileBy.ID,“resource:id”)
- accessibility_id定位
- driver.find_element_by_accessibility_id(content-desc属性值)
- driver.find_element(MobileBy.ACCESSIBILITY_ID,“content_desc:属性”)
- xpath定位
- driver.find_element_by_xpath(xpath属性值)
- classname定位(不推荐)
-
https://www.freeformatter.com/xpath-tester.html #ad-output格式化xml
4.4 uiautomatorviewer定位工具使用
定位工具
- uiautomatorviewer工具(only android)
- 推荐使用
- sdk路径下的工具
- Appium inspector工具
实战演示
- 打开 雪球 app
- 想搜索框输入文本 alibaba
- 获取【阿里巴巴】这只股票的价格
- 判断股票的价格大于120
5. app控件交互
5.1 元素的常用方法
- 点击方法 element.click()
- 输入操作 element.send_keys(“appium”)
- 设置元素的值 element.set_value(“appium”)
- 清除操作 element…clear()
- 是否可见 element.is_displayed() 返回 True/False
- 是否可用 element.is_enabled() 返回 True/False
- 是否被选中 element.is_selected() 返回 True/False
- 获取属性值 get_attribute(name)
- get_attribute()方法能获取的属性,元素的属性几乎都能获取到,属性名称和uiautomatorviewer里面的一致
- 源码地址:https://github.com/appium/appium-uiautomator2-server/blob/master/app/src/main/java/io/appium/uiautomator2/handler/GetElementAttribute.java
- {text,name} text(返回 text)
- {class,className} (返回 class,只有 API=>18才能支持)
- {resource-id,resourceId} (返回resource-id,只有 API=>18才能支持)
- {content-desc,contentDescription} 返回content-desc属性
- checkable,checked,clickable,enabled,focusable,focused,{long-clickable,longClickable},package,password,scrollable,selection-start,selection-end,selected,bounds,displayed,contentSize 返回true or false
- 注意:有些属性展示在uiautomatorviewer里,但是不能通过get_attribute获取,比如:index
5.2 元素的常用属性
- 获取元素文本
- 获取元素坐标
- 格式:element.location
- 结果:{‘y’: 19, ‘x’: 498}
- 获取元素尺寸(高和宽)
- 格式:element.size
- 结果:{‘width’: 500, ‘height’: 22}
案例
- 打开 雪球 应用首页
- 定位首页的搜索框
- 判断搜索框是否可用,并查看搜索框name属性值
- 打印搜索框这个元素的左上角坐标和它的宽高
- 向搜索框输入:alibaba
- 判断【阿里巴巴】是否可见
- 如果可见,打印”搜索成功“点击,如果不可见,打印”搜索失败“
6. 触屏操作自动化
TouchAction
点击
滑动
手势操作
-
TouchAction(driver).press(x=244,y=374).wait(100).move_to(x=711,y=374).wait(100).move_to(x=1198,y=374).wait(100).move_to(x=1198,y=865).wait(100).move_to(x=1198,y=1323).wait(100).release().perform()
7. 高级定位技巧
7.1 Xpath定位进阶
- 层级定位
- 父节点定位子节点
- 子节点定位父节点
- 子节点定位兄弟节点
- 爷爷节点定位孙子节点
Xpath定位
案例演示
- 使用通过Appium desktop 来查找兄弟节点
- 用例
- 打开【雪球】app
- 搜索“alibaba”
- 从搜索结果查找,阿里巴巴[香港股票]的价格
7.2 uiautomator定位表达式
uiautomator定位
- 通过resource-id定位
- 通过classname定位
- 通过content-desc定位
- 通过文本定位
- 组合定位
- 通过父子关系定位
- 通过resourceid定位
- new UiSelector().resourceId(“id”)
- 通过classname定位
- new UiSelector().className(“className”)
- 通过content-desc定位
- new UiSelector().description(“contenet-des属性”)
- 用法:
driver.find_element_by_android_uiautomator(表达式).click()
- 通过文本定位
- 通过text文本定位语法
new UiSelector().text("text文本")
- 如果文本比较长,可以用textContains模糊匹配
new UISelector().textContains("包含text文本")
- 同样可以用textStartsWith是以某个文本开头来匹配
- new UiSelector().textStartsWith(“以text文本开头”)
- 也可以用正则表达式textMatches匹配
- new UiSelector().textMatches(“正则表达式”)
- 组合定位
- 例1:id与text属性组合
id_text = 'resourceId("com.baidu.yuedu:id/webbooktitle").text("小说")'
driver.find_element_by_android_uiautomator(id_text).click()
- 例2:class与text属性组合
class_text = 'className("android.widget.TextView").text("图书")'
driver.find_element_by_android_uiautomator(class_text).click()
- 父子关系定位 childSelector
- 有时候不能直接定位某个元素,但是它的父元素很好定位,这时候就先定位父元素,通过父元素找儿子
son = 'resourceId("com.baidu.yuedu:id/rl_tabs").childSelector(text("股票))'
- 兄弟定位 fromParent
- 有时候父元素不好定位,但是跟他相邻的兄弟元素很好定位,这时候就可以通过兄弟元素,找到同一父级元素下的子元素
brther = 'resourceId("com.baidu.yuedu:id/lefttitle").fromParent(text("用户"))'
- 实现滚动查找元素
'new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().text("查找的文本").instance(0));'
7.3 滑动定位
8. appium显式等待机制
Wait等待
- 强制等待: sleep 不推荐
- 全局隐式等待
- 在服务端等待
driver.implicitly_wait(TIMEOUT)
- 显式等待
- 在客户端等待
WebDriverWait(self.driver, 10).until(expected_conditions.visibility_of_element_located(LOCATOR))
显示等待
- 显式等待
- 显示等待与隐式等待相对,显示等待必须在每个需要等待的元素前面进行声明。
- 是针对于某个特定的元素设置的等待时间,在设置时间内,默认每隔一段时间检测一次当前页面某个元素是否存在,
- 如果在规定的时间内找到了元素,则直接执行,即找到元素就执行相关操作,
- 如果超过设置时间检测不到则抛出异常。默认检测频率为0.5s,默认抛出异常为:NoSuchElementException
- 显示等待用到的两个类:
- WebDriverWait和expected_conditions两个类
- 显式等待可以等待动态加载的ajax元素,显式等待需要使 ExpectedCondtions来检查条件
- 一般页面上元素的呈现
- title出现 首先出现title
- dom树出现 presence,还不完整
- css出现 (可见 visibility)
- js出现,js特效执行 (可点击 clickable)
- html文档是自上而下加载的,
- js文件加载会阻塞Html内容的加载,有些JS异步加载的方式来完成js的加载
- 样式表下载完成之后会跟之前的样式表一起进行解析,会对之前的元素重新渲染
- WebDriverWait用法
WebDriverWait(driver, timeout,poll_frequency=0.5,ignored_exceptions=None)
- driver: 浏览器驱动
- timeout:最长超时时间,默认以秒为单位
- poll_frequency: 检测的间隔步长,默认为0.5s
- ignored_exceptions: 超时后的抛出的异常信息,默认抛出 NoSuchElementExeception异常。
- WebDriverWait 的 until() 和 until_not()方法:
- method: 在等待期间,每隔一段时间(__init__中的poll_frequency)调用这个传入的方法, 直到返回值不是False,
message: 如果超时,抛出 TimeoutException, 将message传入异常
- until_not:与 until相反, until是当某元素出现或什么条件成立则继续执行, until_not是当某元素消失或什么条件不成立,则继续执行,参数也相同。
expected_conditions类
- presence_of_element_located 判断元素是否被加到了DOM树里,并不代表该元素一定可见
- 用法:
WebDriverWait().until(expected_conditions, presence_of_element_located(元素对象))
- visibility_of_element_located 判断某个元素是否可见,可见代表元素非隐藏,并且元素的宽和高都不等于0
- 用法:
WebDriverWait().until(expected_conditions, visibility_of_element_located(元素定位符))
使用lambda表达式
-
WebDriverWait(driver,time).until(lambda x:x.find_element_by_id("someId"))
返回一个元素
显示等待案例
总结三种等待方式
- 隐式等待,尽量默认都加上,时间限定在3-6s,不要太长,为了所有的find_element方法都有一个很好的缓冲
- 显式等待,用来处理隐式等待无法解决的一些问题,比如:文件上传(可以设置长一点),文件上传需要设置20s以上,但是如果设置隐式等待,它会在每个find方法都等这么长时间,一旦发现没有找到元素,就会等20s以后才抛出异常,影响case的执行效率,这时候就需要用显式等待,显式等待可以设置的长一点
- 强制等待:一般不推荐,前两种基本能解决绝大部分问题,如果某个控件没有任何特征,只能强制等待,这种情况比较少
9. 特殊控件toast识别
18
toast控件识别
toast介绍
- Toast,简易的消息提示框
- 为了给当前视图显示一个浮动的显示块,与dialog不同它永远不会获得焦点
- Toast类的思想:尽可能不引人注意,同时还向用户显示信息希望他们看到
- Toast显示的时间有限,Toast会根据用户设置的显示时间后自动消失。
- Toast本身是个系统级别的控件,它归属于系统 settings,当一个app发送消息的时候,不是自己造出来的这个弹框,它是发给系统,,由系统统一进行弹框,这类的控件不在app内,需要特殊的控件识别方法
toast定位
- appium使用uiautomator底层的机制来分析抓取toast,并且把toast放到控件树里面,但本身并不属于控件。
- automationName:uiautomator2
- getPageSource是无法找到的
- 必须使用xpath查找
//*[@class='android.widget.Toast']
//*[contains(@text,"xxxxx")]
-
private void addToastMsgToRoot(CharSequence tokenMSG){
AccessibilityNodeInfo node =AccessibilityNodeInfo .obtain();
node.setText(tokenMSG);
node.setClassName(Toast.class.getName());
node.setPackageName("com.android.settions");
this.children.add(new UiAutomationElement(node /* Accessibil....))
}
toast定位案例
10. appium属性获取与断言
10.1 get attribute原理分析
10.2 属性命名规则
Get_attribute原理分析
源代码
源代码分析
断言
连按此项以编辑
普通断言
hamcrest断言
- github地址:https://github.com/hamcrest/PyHamcrest
- hamcrest框架介绍
- Hamcrest是一个为了测试为目的,能组合成灵活表达式的匹配器类库。用于编写断言的框架,使用这个框架编写断言,提高可读性及开发测试的效率
- Hamcrest提供了大量被称为“匹配器”的方法。每个匹配器都设计用于执行特定的比较操作。
- Hamcrest的可扩展性强,让你能够创建自定义的匹配器。
- 支持多种语言,java,python,ruby,object-c,php,erlang,swift