用户端app自动化测试2

强制等待与隐式等待

为什么要添加等待?

  • 避免页面未渲染完成后操作,导致的报错

直接等待

  • 解决方案:在报错的元素操作之前添加等待
  • 原理:强制等待,线程休眠一定时间
  • time.sleep(3)
from appium import webdriver
import time
desired_caps={}
desired_caps['platformName']='Android'
desired_caps['platformVersion']='6.0'
desired_caps['deviceName']='emulator-5554'
desired_caps['appPackage']='com.xueqiu.android'
desired_caps['appActivity']='com.xueqiu.android.common.MainActivity'
desired_caps['noReset'] = "true"
driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub",desired_caps)
time.sleep(3)
driver.find_element(AppiumBy.ID, \
    "com.xueqiu.android:id/tv_search").click()
time.sleep(3)
driver.find_element(AppiumBy.ID, \
    "com.xueqiu.android:id/search_input_text").send_keys("alibaba")
    
driver.find_element(AppiumBy.ID,\
    "com.xueqiu.android:id/code").click()

driver.quit()

隐式等待

  • 问题:难以确定元素加载的具体等待时间。
  • 解决方案:针对于寻找元素的这个动作,使用隐式等待添加配置。
  • 原理:隐式等待是一种全局的等待方式,设置一个等待时间,轮询查找(默认 0.5 秒)元素是否出现,如果没出现就抛出异常
#设置一个等待时间,轮询查找(默认0.5秒)元素是否出现,如果没出现就抛出异常
driver.implicitly_wait(3)

隐式等待无法解决的问题

  • 元素可以找到,使用点击等操作,出现报错
  • 原因:
    • 页面元素加载是异步加载过程,通常 xml 会先加载完成,相应的元素属性后加载
    • 元素存在与否是由 xml 决定,元素的交互是由属性决定
    • 隐式等待只关注元素能不能找到,不关注元素能否点击或者进行其他的交互
  • 解决方案:使用显式等待

显式等待基本使用(初级)

  • 示例: WebDriverWait(driver实例, 最长等待时间, 轮询时间).until(结束条件)
  • 原理:在最长等待时间内,轮询,是否满足结束条件
  • 注意:在初级时期,先关注使用
WebDriverWait(driver, 10).until(
        expected_conditions.element_to_be_clickable(
        (AppiumBy.ID, 'com.xueqiu.android:id/code')))

driver.find_element(AppiumBy.ID,"com.xueqiu.android:id/code").click()

常见的交互方法

元素的常用方法

  • 点击方法 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 里面的一致
  • get_attribute() 可以获取的属性
    • resource-id/resourceld 返回 resource-id(API=>18 支持)
    • text 返回 text
    • class 返回 class(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

元素常用属性

  • 获取元素文本
    • 格式:element.text
  • 获取元素坐标
    • 格式:element.location
    • 结果:{'y': 19,'x: 498}
  • 获取元素尺寸(高和宽)
    • 格式:element.size
    • 结果:{'width':500,'height':22)

定位策略

选择定位器通用原则

  • 与研发约定的属性优先
    • web 推荐 class
    • android 推荐 content-description
    • ios 推荐 label
  • 身份属性 id,name(web 定位)
  • 组合定位 xpath,css
  • 其它定位

元素定位不到
原因 解决办法
定位不正确 在定位工具中先测试定位表达式是否正确
存在动态 ID 定位方式使用 css 或者 xpath 的相对定位
页面还没有加载完成 添加死等验证,使用显示等待或隐式等待进行优化
页面有 iframe 切换到 iframe 后定位
页面切换 window 切换到对应窗口后定位
要定位元素为隐藏元素 使用 js 操作该元素

混合定位的应用场景

  • 场景:
    • 属性动态变化(id,text)
    • 重复元素属性(id,text,class)
  • 解决:
    • 根据相对位置关系进行定位(css、xpath)(父级,子级,兄弟,索引)
    • 使用 find_elements 遍历查找

使用等待机制的场景

  • 场景
    • 控件动态出现
    • 控件出现特定特征
  • 解决
    • 元素定位结合隐式等待与显式等待

Web 弹框定位

  • 场景
    • web 页面 alert 弹框
  • 解决:
    • web 需要使用 driver.switchTo().alert() 处理

App toast 提示框定位

  • 场景
    • app toast 提示框
  • 解决:
    • 使用 driver.page_source 拿到页面布局结构文件,分析 toast/弹框组件的标签内容,
    • 然后通过 id/text/class 等属性,使用 xpath 完成元素定位
    • 结合 隐式等待

下拉框/日期控件定位

  • 场景:
    • <input>标签组合的下拉框无法定位
    • <input>标签组合的日期控件无法定位
  • 解决:
    • 面对这些元素,我们可以引入 JS 注入技术来解决问题。

文件上传定位

  • 场景:
    • input 标签文件上传
  • 解决:
    • input 标签直接使用 send_keys()方法

Appium Server 安装(Windows)

安装 Node.js

// 查看源
npm config get registry

//更换源
npm config set registry https://registry.npm.taobao.org

版本查看

node -v
npm -v

安装 Appium Server

// 安装最新版本的appium server
npm install -g appium
  • 注意 -g 参数一定要有,不能省,代表全局
  • 安装某个特定的版本npm install -g appium@1.19.1

安装环境检测工具

  • 运行环境检测工具 appium-doctor
# 安装检测工具 appium-doctor
npm install -g appium-doctor

环境检测

  • 执行检测命令 appium-doctor

运行 Appium 服务

// 帮助文档
appium --help

// 运行 appium 服务
appium

Capabilities 进阶

deviceName

  • 只是设备的名字,别名
  • 随便起
  • 不能锁定唯一一个设备

uid

  • 多设备选择的时候,要指定 uid
  • 默认读取设备列表的第一个设备
  • 设备列表获取

adb devices

newCommandTimeout

  • appium 程序应等待来自客户端的新命令多长时间
  • 超时后==会话删除==
  • 默认 60
  • 设置为 0 禁用

autoGrantPermissions

  • 授予启动的应用程序某些权限

PRINT_PAGE_SOURCE_ON_FIND_FAILURE

  • 默认为 false
  • 发生任何错误,强制服务器将实际的 XML 页面源转储到日志中.

测试策略

noReset

  • 默认为false
  • 安卓true
    • 不停止应用程序
    • 不清除应用程序数据
    • 不卸载 apk

fullReset

  • 默认为 falsetrue:新会话之前完全卸载被测应用程序
  • 安卓
    • 在会话开始之前(appium 启动 app)和测试之后停止应用程序
    • 清除应用程序数据并卸载 apk

dontStopAppOnReset

  • 默认为 false
  • 不希望应用程序在运行时重新启动,设置为 true
#打开的app退出后重新启动
adb shell am start -S 包名/activity名

#打开的app不需要退出,直接使用当前页面
adb shell am start 包名/activity名