环境准备:https://www.cnblogs.com/yuntimer/p/17019315.html

获取 app 的信息

  • app 入口,两种方式获取:
    • 1、通过 logcat 日志获取
      • Mac/Linux: adb logcat ActivityManager:I | grep “cmp"
      • Windows: adb logcat ActivityManager:I | findstr "cmp"
    • 2、通过 aapt 获取
      • Mac/Linux: aapt dump badging wework.apk | grep launchable-activity
      • Windows: aapt dump badging wework.apk | findstr launchable-activity
  • 启动应用命令 adb shell am start -W -n <package-name>/<activity-name> -S

配置待测应用

  • platformName:平台,Android/iOS
  • deviceName:设备名
  • appPackage:应用的包名
  • appActivity:应用的页面名 Activity
  • noReset: 防止清空缓存信息

Appium inspector 页面功能键

  • SelectElements:选中元素,查看层级和属性
  • Swipe By Coordinates:通过坐标点滑动
  • Tap By Coordinates:通过坐标点点击
  • Back:返回
  • Refresh Source & Screenshot:刷新页面
  • StartRecording:开始录制脚本
  • Search for element:搜索元素
  • Copy XML Source to Clipboard:复制 xml 结构
  • Quit Session & Close Inspector:退出当前 Session

capability 配置参数解析

官方解释:http://appium.io/docs/en/writing-running-appium/caps/

  • 功能:配置 Appium 会话,告诉 Appium 服务器需要自动化的平台的应用程序

  • 形式:键值对的集合,键对应设置的名称,值对应设置的值

  • 主要分为三部分

  • 1、公共部分

描述
platformName 使用的手机操作系统 iOS,Android,或者 Firefox0S
platformVersion 手机操作系统的版本 例如 7.14.4
deviceName 使用的手机或模拟器类型 iPhone SimulatoriPad SimulatoriPhone Retina 4-inchAndroid EmulatorGalaxy S4, 等等…. 在 iOS 上,使用 Instruments
的 instruments -s devices 命令可返回一个有效的设备的列表。
在 Andorid 上虽然这个参数目前已被忽略,但仍然需要添加上该参数
automationName 使用哪个自动化引擎 android默认使用uiautomator2ios默认使用XCUTest
noReset 在当前 session 下不会重置应用的状态。默认值为 false truefalse
udid 连接的真实设备的唯一设备编号 (Unique device identifier) 例如 1ae203187fc012gg
    2、ios 部分
描述
bundleId 被测应用的 bundle ID 。用于在真实设备中启动测试,也用于使用其他需要 bundle ID 的关键字启动测试。在使用 bundle ID 在真实设备上执行测试时,你可以不提供 app 关键字,但你必须提供 udid 。 例如 io.appium.TestApp
autoAcceptAlerts 当 iOS 的个人信息访问警告 (如 位置、联系人、图片) 出现时,自动选择接受( Accept )。默认值 false true 或者 false
showIOSLog 是否在 appium 日志中显示从设备捕获的任何日志。默认 false true or false
    3、android 部分
描述
appActivity Activity 的名字是指从你的包中所要启动的 Android acticity。他通常需要再前面添加. (例如 使用 .MainActivity 代替 MainActivity MainActivity.Settings
appPackage 运行的 Android 应用的包名 com.example.android.myAppcom.android.settings
appWaitActivity 用于等待启动的 Android Activity 名称 SplashActivity
unicodeKeyboard 启用 Unicode 输入,默认为 false true or false
resetKeyboard   true or false
dontStopAppOnReset 首次启动的时候,不停止 app true or false
skipDeviceInitialization 跳过安装,权限设置等操作 true or false

用例结构分析

  • 添加 capability 信息
  • 初始化webdriver,添加setupteardown
  • 添加隐式等待和noReset属性增强用例稳定性
  • 添加断言

 1 import time
 2 from appium import webdriver
 3 from appium.webdriver.common.mobileby import MobileBy
 4 
 5 
 6 class TestDemo:
 7     def setup(self):
 8         desire_cap = {}
 9         # 平台
10         desire_cap['platform'] = 'Android'
11         # 设备名
12         desire_cap['deviceName'] = 'emulator'
13         # app 包名
14         desire_cap['appPackage'] = 'io.appium.android.apis'
15         # app 页面名
16         desire_cap['appActivity'] = '.ApiDemos'
17         self.driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desire_cap)
18         self.driver.implicitly_wait(10)
19 
20     def teardown(self):
21         time.sleep(3)
22         # 退出应用
23         self.driver.quit()
24 
25     def test_api_demo(self):
26         """
27         1、打开 API demo apk
28         2、点击 OS 控件
29         3、点击 Morse Code 控件
30         4、在搜索框中输入 阿里巴巴
31         5、返回到第一页
32         6、断言
33         :return:
34         """
35         # 点击 OS 控件
36         self.driver.find_element_by_accessibility_id("OS").click()
37         # 点击 Morse Code 控件
38         self.driver.find_element_by_accessibility_id("Morse Code").click()
39         # 输入`阿里巴巴`
40         self.driver.find_element_by_id("io.appium.android.apis:id/text").clear()
41         self.driver.find_element_by_id("io.appium.android.apis:id/text").send_keys("阿里巴巴")
42         # 返回第一页
43         self.driver.back()
44         self.driver.back()
45         self.driver.back()
46         # 选择元素进行断言
47         result = self.driver.find_element(MobileBy.XPATH,"//*[@resource-id='android:id/text1'][1]")
48         print(result.text)
49         # 断言
50         assert result.text == "阿里巴巴"

完整脚本

常见控件定位方法

Selenium提供了八种定位方式:https://www.selenium.dev/documentation/webdriver/elements/locators/

方式 描述
class name class 属性对应的值
css selector(重点) css 表达式
id(重点) id 属性对应的值
name(重点) name 属性对应的值
link text 查找其可见文本与搜索值匹配的锚元素
partial link text 查找其可见文本包含搜索值的锚元素。如果多个元素匹配,则只会选择第一个元素。
tag name 标签名称
xpath(重点) xpath表达式
  • driver.find_element(By.ID, "ID属性对应的值")
  • driver.find_element(By.NAME, "Name属性对应的值")
  • driver.find_element(By.CSS_SELECTOR, "css表达式")
  • driver.find_element(By.XPATH, "xpath表达式")
  • driver.find_element(By.LINK_TEXT,"文本信息")

强制等待与隐式等待

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

1、直接等待:time.sleep(3)

  解决方案:在报错的元素操作之前添加等待

  原理:强制等待,线程休眠一定时间

2、隐式等待:driver.implicitly_wait(3)

  解决方案:针对于寻找元素的这个动作,使用隐式等待添加配置。

  原理:设置一个等待时间,轮询查找(默认0.5秒)元素是否出现,如果没出现就抛出异常

3、显式等待

  • 元素可以找到,使用点击等操作,出现报错
  • 原因:
    • 页面元素加载是异步加载过程,通常html会先加载完成,js、css其后
    • 元素存在与否是由HTML决定,元素的交互是由css或者js决定
    • 隐式等待只关注元素能不能找到,不关注元素能否点击或者进行其他的交互
  • 示例: WebDriverWait(driver实例, 最长等待时间, 轮询时间).until(结束条件)
  • 如:WebDriverWait(driver, 10).until( expected_conditions.element_to_be_clickable( (By.CSS_SELECTOR, ‘#success_btn’)))
  • 原理:在最长等待时间内,轮询,是否满足结束条件
类型 使用方式 原理 适用场景
直接等待 time.sleep(等待时间)) 强制线程等待 调试代码,临时性添加
隐式等待 driver.implicitly_wait(等待时间) 在时间范围内,轮询查找元素 解决找不到元素问题,无法解决交互问题
显式等待 WebDriverWait(driver实例, 最长等待时间, 轮询时间).until(结束条件) 设定特定的等待条件,轮询操作 解决特定条件下的等待问题,比如点击等交互性行为

 自动化测试定位策略(待补充)

实践练习:

1、用例编写思路

  • pytest 测试框架编写
  • 添加隐式等待
  • 添加 setup teardown
  • 添加断言

2、代码示例

 1 from appium import webdriver
 2 from appium.webdriver.common.mobileby import MobileBy
 3 
 4 # 打开【雪球】应用首页
 5 # 点击搜索框(点击之前,判断搜索框的是否可用,并查看搜索框 name 属性值,并获取搜索框坐标,以及它的宽高)
 6 # 向搜索框输入:alibaba
 7 # 判断【阿里巴巴】是否可见
 8 # 如果可见,打印“搜索成功”
 9 # 如果不可见,打印“搜索失败
10 
11 class TestXueQiu:
12     def setup(self):
13         desired_caps = {}
14         desired_caps['platformName'] = 'Android'
15         desired_caps['platformVersion'] = '10'
16         desired_caps['deviceName'] = 'emulator-5554'
17         desired_caps['appPackage'] = 'com.xueqiu.android'
18         desired_caps['appActivity'] = '.view.WelcomeActivityAlias'
19         desired_caps['noReset'] = 'true'
20         self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
21         self.driver.implicitly_wait(10)
22 
23     def teardown(self):
24         self.driver.quit()
25 
26     def test_search(self):
27         element = self.driver.find_element(MobileBy.ID,"com.xueqiu.android:id/tv_search")
28         search_enabled = element.is_enabled()
29         print(f"搜索框的文本:{element.text},搜索框的坐标:{element.location},搜索框的size:{element.size}")
30 
31         if search_enabled == True:
32             element.click()
33             self.driver.find_element(MobileBy.ID,
34                                      "com.xueqiu.android:id/search_input_text").\
35                 send_keys("alibaba")
36             alibaba_element = self.driver.find_element(MobileBy.XPATH, "//*[@text='阿里巴巴']")
37             # alibaba_element.is_displayed()
38             displayed = alibaba_element.get_attribute("displayed")
39             assert displayed == "true"
40         else:
41           assert False

脚本示例

 

2023-1-2笔记

 

版权声明:本文为三天乐趣原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/yuntimer/p/17020313.html