移动端UI自动化之appium的使用(二)
一、appium属性获取与断言
1.1、get_attrbute原理分析
官网:https://appium.io/docs/en/commands/element/attributes/attribute/
所有可以获取的属性
CHECKABLE(new String[]{"checkable"}),
CHECKED(new String[]{"checked"}),
CLASS(new String[]{"class", "className"}),
CLICKABLE(new String[]{"clickable"}),
CONTENT_DESC(new String[]{"content-desc", "contentDescription"}),
ENABLED(new String[]{"enabled"}),
FOCUSABLE(new String[]{"focusable"}),
FOCUSED(new String[]{"focused"}),
LONG_CLICKABLE(new String[]{"long-clickable", "longClickable"}),
PACKAGE(new String[]{"package"}),
PASSWORD(new String[]{"password"}),
RESOURCE_ID(new String[]{"resource-id", "resourceId"}),
SCROLLABLE(new String[]{"scrollable"}),
SELECTION_START(new String[]{"selection-start"}),
SELECTION_END(new String[]{"selection-end"}),
SELECTED(new String[]{"selected"}),
TEXT(new String[]{"text", "name"}),
// The main difference of this attribute from the preceding one is that
// it does not replace null values with empty strings
ORIGINAL_TEXT(new String[]{"original-text"}, false, false),
BOUNDS(new String[]{"bounds"}),
INDEX(new String[]{"index"}, false, true),
DISPLAYED(new String[]{"displayed"}),
CONTENT_SIZE(new String[]{"contentSize"}, true, false);
def test_get_attr(self):"""获取属性"""search_ele = self.driver.find_element_by_id('com.xueqiu.android:id/tv_search')print(search_ele.get_attribute('content-desc'))print(search_ele.get_attribute('text'))print(search_ele.get_attribute('resource-id'))print(search_ele.get_attribute('clickable'))print(search_ele.get_attribute('enabled'))print(search_ele.get_attribute('bounds'))
1.2、断言
1.2.1、普通断言 assert
如果存在两个assert,则第一个assert断言失败,就不会执行第二个断言。
1.2.2、Hamcrest断言
github地址:https://github.com/hamcrest/PyHamcrest
安装:pip install PyHamcrest
hamcrest 框架介绍
- Hamcrest是一个为了测试为目的,能组合成灵活表达式的匹配器类库。用于编写断言的框架,使用这个框架编写断言,提高可读性及开发测试的效率。
- Hamcrest提供了大量被称为“匹配器”的方法。每个匹配器都设计用于执行特定的比较操作。
- Hamcrest的可扩展性强,让你能够创建自定义的匹配器。
def test_hamcrest(self):"""hamcrest断言"""assert_that(10, equal_to(10))assert_that(10.0, close_to(10.0, 0.25))
二、appium参数化用例
雪球app下载,提取码:cd8v
import pytest
from appium import webdriver
from appium.webdriver.common.mobileby import MobileBy
from hamcrest import *class TestParam:def setup(self):des_caps = {'platformName': 'Android','platformVersion': '7.1.2','deviceName': '127.0.0.1:62001','appPackage': 'com.xueqiu.android','appActivity': '.common.MainActivity','unicodeKeyboard': True,'resetKeyboard': True,'noReset': True,'dontStopAppOnReset': True,'skipDeviceInitialization': True}self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', des_caps)self.driver.implicitly_wait(10)def teardown(self):# 点击取消self.driver.find_element(MobileBy.ID, 'com.xueqiu.android:id/action_close').click()self.driver.quit()@pytest.mark.parametrize('name, code, expect', [('阿里巴巴', 'BABA', 230),('小米集团', '01810', 27)])def test_param(self, name, code, expect):"""参数化1、打开 雪球 app2、点击搜索输入框3、向搜索框里面输入搜索词4、在搜索结果里面选择第一个搜索结果,然后进行点击5、获取股价,并判断这只股价的价格:return:"""self.driver.find_element(MobileBy.ID, 'com.xueqiu.android:id/tv_search').click()self.driver.find_element(MobileBy.ID, 'com.xueqiu.android:id/search_input_text').send_keys(name)self.driver.find_element(MobileBy.ID, 'com.xueqiu.android:id/name').click()current_price = self.driver.find_element(MobileBy.XPATH,f'//*[@text="{code}"]/../../..'f'//*[@resource-id="com.xueqiu.android:id/current_price"]').textcurrent_price = float(current_price)print(current_price)assert_that(current_price, close_to(expect, 10))
三、Android webview测试
appium支持 Native App(原生)、Hybrid App(混合)、Web App(H5)三种应用。
上下文
原生:NATIVE_APP
H5: WEBVIEW_xxx
3.1、环境准备
手机端:被测浏览器(不可以是第三方浏览器,一般使用自带的浏览器),IOS:Safari、Chrome,Android:Chromium,Browser
PC端:安装Chrome浏览器(或chromium),并且能登录https://www.google.com/
下载对应手机浏览器对应的driver版本:
- 国内镜像地址:https://npm.taobao.org/mirrors/chromedriver/
- appium github:https://github.com/appium/appium/blob/master/docs/cn/writing-running-appium/web/chromedriver.md
获取手机默认浏览器的版本:
mac/linux 只需要把findstr改成grep即可
C:\Users\18367>adb shell pm list package |findstr webview <== 获取webview的包名
package:com.google.android.webviewC:\Users\18367>adb shell pm dump com.google.android.webview |findstr version <== 默认浏览器的版本versionCode=377014315 minSdk=0 targetSdk=29versionName=75.0.3770.143 <== 默认浏览器的版本
下载最接近的驱动版本,这个版本是支持75版本的。
启动参数:
appium默认有个驱动版本,但是和手机或者模拟器版本不匹配,需要通过chromedriverExecutable参数指定对应的驱动。
'browserName'='Browser' 或者 'browserName'='Chrome'
'chromedriverExecutable'='指定驱动路径'
3.2、元素定位
使用谷歌浏览器需要科学上网什么的,比较麻烦,建议可以使用最新版本的edge浏览器。
edge浏览器中输入edge://inspect
,点击对应的网页的inspect,进入调试模式,查找元素定位。
from os.path import dirname, joinfrom appium.webdriver.common.mobileby import MobileBy
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from time import sleepfrom appium import webdriverclass TestBrowser:def setup(self):des_caps = {'platformName': 'Android','platformVersion': '7.1.2','deviceName': '127.0.0.1:62001','browserName': 'Browser','chromedriverExecutable': join(dirname(__file__), 'driver', 'chromedriver.exe'),'noReset': True,}self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', des_caps)self.driver.implicitly_wait(10)def teardown(self):self.driver.quit()def test_browser(self):self.driver.get('https://m.baidu.com/')sleep(5)self.driver.find_element(MobileBy.ID, 'index-kw').click()WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((MobileBy.ID, 'index-kw'))).send_keys('appium')WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((MobileBy.ID, 'index-bn'))).click()sleep(5)
3.3、Android混合页面测试
混合应用就是在原生的页面中嵌入了H5页面。
如何判断页面是webview
- 断网查看
- 看加载条
- 看顶部是否有关闭按钮
- 下拉刷新,页面是否刷新
- 下拉刷新的时候是否有网页提供方
- 用工具查看
webview
- android系统提供能显示网页的系统控件(特殊的view)
- <Android 4.4 WebView底层实现WebKit内核
=Android 4.4 Google采用chromium作为系统WebView底层支持,API没变,支持H5、CSS3、js
前提条件
PC
- 浏览器能访问:https://www.google.com/,edge浏览器也可以定位原生
- chromedriver下载对应的版本
手机端:应用app需要打开webview开关,android 6.0 不开启webview也可以获取html结构
代码
- appPackage,appActivity
- 启动参数里面添加:chromedriverExecutable参数,指定驱动的版本的路径
通过appium日志查看Chromedriver日志,查看手机内置浏览器的chrome版本。
示例
from os.path import join, dirname
from time import sleepfrom appium import webdriver
from appium.webdriver.common.mobileby import MobileBy
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as ECclass TestWebView:def setup(self):des_caps = {'platformName': 'Android','platformVersion': '7.1.2','deviceName': '127.0.0.1:62001','udid': '127.0.0.1:62001','appPackage': 'com.xueqiu.android','appActivity': '.common.MainActivity','chromedriverExecutable': join(dirname(__file__), 'driver', 'chromedriver224.exe'),'unicodeKeyboard': True,'resetKeyboard': True,'noReset': True,'dontStopAppOnReset': True,'skipDeviceInitialization': True}self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', des_caps)self.driver.implicitly_wait(10)def teardown(self):self.driver.quit()def test_webview(self):""":return:"""self.driver.find_element(MobileBy.XPATH, '//*[@text="交易"]').click()# 切换上下文self.driver.switch_to.context(self.driver.contexts[-1])print(self.driver.page_source)# 进入港美股开户页面WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((MobileBy.XPATH, '//*[@text()="港美股开户"]'))).click()# 切换句柄,每打开一个网页,就会有一个新的句柄self.driver.switch_to.window(self.driver.window_handles[-1])WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((MobileBy.XPATH, '//*[text()="请输入手机号"]'))).send_keys('13000000000')self.driver.find_element(MobileBy.XPATH, '//*[text()="请输入验证码"').send_keys('1234')self.driver.find_element(MobileBy.XPATH, '//*[text()="立即开户"').send_keys('1234')
常遇到的坑
设备
- android模拟器6.0默认支持webview操作(mumu不可以,genimotion和sdk自带的emulator可以)
- 其它模拟器和物理机需要打开app内开关(webview调试开关)
PC浏览器定位元素
- chrome浏览器-Chrome 62 才可以更好的看见webview的内部,其它版本都有bug
- 也换成chromeium浏览器可以避免很多坑,展示效果和速度都比chrome要快
代码
- 有的设备可以直接使用find_element_by_accessibility_id(),不同的设备渲染的页面不同,兼容性不适合
- switch_to.context():切换上下文
- switch_to.window():切换句柄
多版本的驱动处理
添加启动参数:chromedriverExecutableDir,会自动找匹配的驱动版本,前提是文件夹下有这个匹配的驱动。
'chromedriverExecutableDir': join(dirname(__file__), 'driver')
添加json配置文件,指定版本映射,通过chromedriverChromeMappingFile 参数指定对应json文件,添加到启动参数中
driver.json文件
{"2.42": "63.0.3239","2.41": "62.0.3202"
}
'chromedriverChromeMappingFile': join(dirname(__file__), 'driver', driver.json)
先通过chromedriverChromeMappingFile获取对应版本的映射驱动,再在chromedriverExecutableDir目录中找对应的驱动。
四、微信小程序测试
4.1、小程序的运行环境
微信小程序运行在多种平台上:iOS(iPhone/iPad) 微信客户端、Android 微信客户端、PC 微信客户端、Mac 微信客户端和用于调试的微信开发者工具。
各种平台脚本执行环境以及用于渲染非原生组件的环境是各不相同的:
- 在iOS上,小程序逻辑层的javascript代码运行在JavaScriptCore中,视图层是由WKWebView来渲染的,环境有iOS12、iOS13等。
- 在Android上,小程序逻辑层的javascript代码运行在V8中,视图层是由自研XWeb引擎基于Mobile Chrome 内核来渲染的。
- 在开发工具上,小程序逻辑层的javascript代码是运行在NWJS中,视图层是由Chrome WebView来渲染的。
4.2、平台差异
尽管各运行环境是十分相似的,但是还是有些许区别:
- JavaScript 语法和 API 支持不一致:语法上开发者可以通过开启 ES6 转 ES5 的功能来规避;此为,小程序基础库内置了必要的Polyfill,来弥补API的差异。
- WXSS渲染表现不一致:尽管可以通过开启样式补偿来规避大部分的问题,还是建议开发者需要在iOS和Android上分别检查小程序的真实表现。
4.3、微信调试开关
微信每个版本都很"善变"
- 可手工开启调试开关
- 默认关闭了调试开关而且无法开启
- 默认开启调试开关
手工开启办法
- 文件传输助手发送
- debugtbs.qq.com
- debugx5.qq.com
- 打开微信小程序调试开关
4.4、微信小程序自动化测试
关键步骤
- 设置chromedriver正确版本
- 设置chrome option 传递给 chromedriver
- 使用 adb proxy 解决 fix chromedriver的bug
为什么有些手机无法自动化微信小程序
- 低版本的chromedriver在高版本的手机上有bug
- chromedriver与微信定制的chrome内核实现上有问题
解决方案:fix it
- chromedriver没有使用adb命令,而是使用了adb协议
- 参考adb proxy源代码
mitmdump -p 5038 --rawtcp --mode reverse:http://localhost:5037/ -s adb_proxy.py
微信小程序自动化测试辅助工具adb proxy
from mitmproxy.utils import strutils
from mitmproxy import ctx
from mitmproxy import tcpdef tcp_message(flow: tcp.TCPFlow):message = flow.messages[-1]old_content = message.content#message.content = old_content.replace(b"foo", b"bar")# 核定代码,替换符合微信的webviewmessage.content = old_content.replace(b"@webview_devtools_remote_", b"@.*.*.*._devtools_remote_")ctx.log.info("[tcp_message{}] from {} to {}:\n{}".format(" (modified)" if message.content != old_content else "","client" if message.from_client else "server","server" if message.from_client else "client",strutils.bytes_to_escaped_str(message.content)))
五、Capability高级用法
更多详细功能参考官网中文文档
newCommandTimeout:用于客户端在退出或者结束 session 之前,Appium 等待客户端发送一条新命令所花费的时间(秒为单位),默认是60秒
udid:连接真机的唯一设备号,支持多设备运行。
autoGrantPermissions:让Appium自动确定您的应用需要哪些权限,并在安装时将其授予应用。默认设置为 false
测试策略相关
- noReset:在当前 session 下不会重置应用的状态。默认值为 false
- fullReset:(iOS)删除所有的模拟器文件夹。(Android) 要清除 app 里的数据,请将应用卸载才能达到重置应用的效果。在 Android, 在 session 完成之后也会将应用卸载掉。默认值为 false
- dontStopAppOnReset:在使用 adb 启动应用之前,不要终止被测应用的进程。如果被测应用是被其他钩子(anchor)应用所创建的,设置该参数为 false 后,就允许钩子(anchor)应用的进程在使用 adb 启动被测应用期间仍然存在。换而言之,设置 dontStopAppOnReset 为 true 后,我们在 adb shell am start 的调用中不需要包含 -S标识(flag)。忽略该 capability 或 设置为 false 的话,就需要包含 -S 标识(flag)。默认值为 false
性能相关
- skipServerInstallation:跳过 uiautomator2 server的安装,非首次启动使用
- skipDeviceInitialization:跳过设备初始化
- skipUnlock:
- skipLogcatCapture:跳过日志的获取
- systemPort:
- ignoreUnimportantViews:跳过不重要的组件获取
- -relaxed-security:启动的时候设置
移动端UI自动化之appium的使用(二)相关推荐
- 基于JAVA实现的WEB端UI自动化 - WebDriver高级篇 - 关联
文章目录 关联 (公共变量传递一些值) 基于JAVA实现的WEB端UI自动化 -自动化测试简单介绍 基于JAVA实现的WEB端UI自动化 - WebDriver基础篇 - 实现简单的浏览器操作 基于J ...
- appium学习总结11 - 移动端UI自动化基础梳理
文章目录 1.appium == app + selenium 2.移动自动化测试基础有哪些? 3.移动自动化测试框架? 4.学习自动化测试的关键点和难点是什么? 5.UI自动化的价值在哪? 6.常见 ...
- 移动端UI自动化Appium测试——Appium server两种启动方式
执行自动化测试之前,需要先运行appium server,这样才能形成server与java client的通信,启动server有两种方式,一种是命令,一种是按钮图标,具体使用如下: 1.用命令启动 ...
- 移动端UI自动化相关环境配置
1.adb环境搭建 1.1jdk 安装 官⽹:https://www.oracle.com/java/technologies/downloads/ 下载18版本,记住java安装⽬录,后⾯我们需要 ...
- LuckyFrameWeb测试平台(一款支持接口自动化、WEB UI自动化、APP自动化,并且支持分布式测试的全纬度免费开源测试平台)
官网:luckyframe.cn 源码地址:https://gitee.com/seagull1985/LuckyFrameWeb 分布式测试:使用Web-Client的方式,Web端负责基本信息管理 ...
- pythonapp自动化_基于python的App UI自动化环境搭建
Android端Ui 自动化环境搭建 一,安装JDK.SDK 二,添加环境变量 Widows: 1.系统变量→新建 JAVA_HOME 变量 E:\Java\jdk1.7.0 jdk安装目录 2.系统 ...
- IM场景的移动端UI自动化测试平台实践
在公司做了两三年IM平台开发,基本上把IM的所有能力都搭建齐全了:单聊.群聊.文本消息.语音消息.视频消息.卡片消息.音视频通话等,而且把整个聊天页面各个区域都开放了出去.整个IM系统的框架以及开发流 ...
- git关闭密码自动存储_RobotFramework实战篇PC端web自动化demo及持续集成
自己学习自动化的话,除了要选好一款框架之外,还要选好一个用来练习的项目.这里小编推荐新手入门可以考虑一下Robotframework这个框架,原因:该框架的学习成本比较低,很多功能都是现成的,而且脚本 ...
- python+uiautomator2 UI自动化
python+uiautomator2 UI自动化 uiautomator2 是一个可以使用Python对Android设备进行UI自动化的库. 其底层基于Google uiautomator,Goo ...
最新文章
- Json string to object debug - json字符串转Java对象的处理调试
- python程序启动其他python程序,如何使用Python启动应用程序的实例?
- 牛津、剑桥、OpenAI联合发出AI预警《人工智能的恶意使用》
- 图解Public,protected ,private和什么也不填的区别
- MetaTransformer:简单到尴尬的视觉模型
- Python import导入模块与函数方法 Python语言基础【1】
- html如何整齐排列选择框,html – 如何均匀地排列多个内嵌块元素?
- 服务器搭建mutt邮件发送环境
- SMS动态查询部署安装XPSP3补丁
- linux进程控制(一)--unix环境高级编程读书笔记
- 【物联网中间件平台-03】YFIOs安装指南
- 2022年度成都市工程系列专业技术高级职称申报评审工作内容及所需材料
- PowerDesign逆向生成数据表结构PDM文件
- 浅谈互联网寒冬与经济形势
- 亚马逊SP-API市场端点接口文档整理
- Android手机开发课程设计之记事本
- FINN(三)BNN在FPGA上的准确性和峰值性能
- MQ-3酒精模拟量 电压转换公式
- 逆波兰式求值 —Java
- 大数据系统包含哪些组件?需要过等保吗?