自动化测试之路 —— Appium元素定位

2023-03-05 10:44:24 浏览数 (2)

阅读目录

  • 1.目的
  • 2.说明
  • 3.接上回
  • 4.定位原理
  • 5. 定位方式
    • 5.1 id定位
    • 5.2 className定位
    • 5.3 content-desc 定位
    • 5.4 Android Uiautomator定位
      • 5.4.1 text定位
      • 5.4.2 text模糊定位
      • 5.4.3 text正则匹配定位
      • 5.4.4 resourceId定位
      • 5.4.5 resourceId正则匹配定位
      • 5.4.6 className定位
      • 5.4.7 className正则匹配定位
      • 5.4.8 组合定位
    • 5.5 xpath定位
      • 5.5.1 唯一属性定位
      • 5.5.2 模糊匹配定位
      • 5.5.3 组合定位
      • 5.5.4 层级定位
  • 6. 注意点

1.目的

  当今社会,人们的生活几乎已经无法离开形形色色的APP了,它提供给我们的便利与服务意义远远超出了其本身的软件价值。作为测试来说移动应用也早已是各大互联网公司的拳头产品,其本身的开发周期短,附属产品价值高等特性决定了今后的主导地位。

  那么在日常的测试活动中,移动应用的质量保障就成为了各个测试团队的主要课题,面对高速迭代的功能、日益缩短的项目周期、逐渐庞大的人力与资源投入,以上的这些因素都会让测试团队不得不在项目中加入自动化测试策略。

  Appium作为一个自动化移动应用测试框架来说,就可以很好的满足大部分移动应用测试的需求。作为当今仍然主流的自动化测试框架,各位测试同学要熟练的使用也就成为大家日常的基本内容之一。

2.说明

  1.此笔记的中所使用的操作系统为Win 10,笔记中所涉及的软件版本有可能会因为时间的推移而导致不匹配或其他额外的操作,请大家有针对性的选择阅读与参考。   2.这里因操作系统关系,只针对安卓与鸿蒙OS来进行教程讲解,后续会推出iOS的相关Appium安装与配置、日常使用教程。   3.本文是使用Python语言配合Appium进行讲解,其他语言相关教程不在此做赘述。

3.接上回

  前一篇我们使用Appium成功启动了对应的被测APP,那么接下来我们将对自动化APP测试中非常重要的一环:元素定位进行深入的探索和实践。

4.定位原理

  我们一般使用Python或Java语言调用相关的Client,那么Appium里就会通过Webdriver协议(Selenium里同样)在应用层进行HTTP方式的数据请求,那么收到请求的手机上的Appium APP的Server就会解析相关的请求并且使用Appium提供的相应自动化测试方法去驱动手机做出相应的操作。

5. 定位方式

  由于每家公司的开发人员的编码规范与习惯各不相同,从而也导致了相关代码中的元素属性会有不同程度的重复或置空。那我们在日常测试脚本的编写与维护中也必须根据不同的代码现状进行定位方式的合理选择。

5.1 id定位

id或者叫resource-id,一般来说是唯一值,使用Inspector就可以定位到,查到值之后可以使用搜索查看下是否唯一。

实现方法: driver_setup()方法可自定义构造,不必相同。 find_element_by_xxxxx 此类方法已弃用,需使用AppiumBy中的各类元素定位方法即可。

代码语言:javascript复制
# -*- coding: UTF-8 -*-
from appium import webdriver
from base.base_driver import driver_setup
from appium.webdriver.common.appiumby import AppiumBy

driver = webdriver.Remote('http://localhost:4723/wd/hub', driver_setup())
# 方法已废弃
driver.find_element_by_id('com.jiyong.rta.debug:id/edt_customer_name')
# find_element用此方法
driver.find_element(AppiumBy.ID('com.jiyong.rta.debug:id/edt_customer_name'))

5.2 className定位

className一般用来决定元素的类型属性,但不推荐使用,界面中相同类型的元素重复的几率较高,无法快速定位到所需要的元素,使用率较低。

实现方式:

代码语言:javascript复制
driver.find_element(AppiumBy.CLASS_NAME('android.widget.EditText'))

5.3 content-desc 定位

这个是用来描述当前元素的功能的,类似于备注。但绝大多数情况下,除非硬性规定,这个属性值一般为空,所以实用性不高。

实现方法:

代码语言:javascript复制
driver.find_element(AppiumBy.ACCESSIBILITY_ID('这是一个按钮'))

5.4 Android Uiautomator定位

这个是Android特有的定位方式,使用的是UiAutomator Api去递归搜索元素,万金油一般的存在,很多无法靠以上定位方法定位的元素就可以试试使用Android Uiautomator来进行定位。

这只介绍比较常用的Uiautomator的定位方法:

5.4.1 text定位

实现方法:

代码语言:javascript复制
driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, 'new UiSelector().text("请输入顾客姓名")')

5.4.2 text模糊定位

定位text较长的元素时,就可以使用模糊匹配的方法textContains来进行元素的定位。

实现方法:

代码语言:javascript复制
driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, 'new UiSelector().textContains("姓名")')

5.4.3 text正则匹配定位

实现方法:

代码语言:javascript复制
driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, 'new UiSelector().textMatches("^请输入.*")')

5.4.4 resourceId定位

实现方法:

代码语言:javascript复制
find_element(AppiumBy.ANDROID_UIAUTOMATOR, 'new UiSelector().resourceId("com.jiyong.rta.debug:id/edt_customer_name")')

5.4.5 resourceId正则匹配定位

实现方法:

代码语言:javascript复制
driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, 'new UiSelector().resourceIdMatches(". edt_customer_name")')

5.4.6 className定位

实现方法:

代码语言:javascript复制
driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, 'new UiSelector().className("android.widget.EditText")')

5.4.7 className正则匹配定位

实现方法:

代码语言:javascript复制
driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, 'new UiSelector().classNameMatches(".*EditText")')

5.4.8 组合定位

实现方法:

代码语言:javascript复制
# id与text组合
driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, 'new UiSelector().resourceId("com.jiyong.rta.debug:id/edt_customer_name").text("顾客名称")')

# className与text组合
driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, 'new UiSelector().className("android.widget.EditText").text("顾客名称")')

5.5 xpath定位

这种定位方式是比较万能的,但万能是相对的,如果在前几种都不太好定位的情况下,我们推荐使用xpath定位方式,只不过极度不推荐使用绝对路径的定位方式,大量的绝对路径定位方式会使脚本或框架在后期的维护上造成很大的难度与较高的成本。所以如果要使用xpath定位方法就比较推荐以下几种方法。

5.5.1 唯一属性定位

如果页面中属性的text或id是固定且唯一的,可以使用以下方法。

实现方法:

代码语言:javascript复制
# text属性唯一
driver.find_element(AppiumBy.XPATH('//*[@text="顾客名称"]'))

这里的 // 指的是相对路径,* 代表匹配所有,@ 是查找对应的指定属性,这里是通过text来定位的所以就在@后面填写text,之后跟上具体的属性值即可。

代码语言:javascript复制
# id属性唯一
driver.find_element(AppiumBy.XPATH('//*[@resource-id="com.jiyong.rta.debug:id/edt_customer_name"]'))
代码语言:javascript复制
# class属性唯一
driver.find_element(AppiumBy.XPATH('//*[@class="android.widget.EditText"]'))

5.5.2 模糊匹配定位

与text中的模糊匹配类似,是在不太清楚具体xpath路径时或具体值可能变动的情况下快速定位匹配的方法。

实现方法:

代码语言:javascript复制
# 以text属性为例,class、id方法类似
driver.find_element(AppiumBy.XPATH('//*[contains(@text="新增")]'))

5.5.3 组合定位

顾名思义,一个元素的多个元素可以通过xpath同时进行指定惊喜感定位。

实现方法:

代码语言:javascript复制
# id和text属性
driver.find_element(AppiumBy.XPATH('//*[@resource-id="com.jiyong.rta.debug:id/edt_customer_name" and @text="顾客名称"]'))

其他的组合以此类推

5.5.4 层级定位

如果出现某一个元素基本没有什么属性值,往往只有一个重复属性的时候,我们可以使用层级定位的方式来帮助我们进行快速定位元素。无论层级是从上到下还是从下到上(父子)只需要按照你指定的顺序进行编写就行。

实现方式:

代码语言:javascript复制
# 通过某一个元素搜索下级元素或上级元素
driver.find_element(AppiumBy.XPATH('//*[@resource-id="com.jiyong.rta.debug:id/edt_customer_name"]/android.widget.EditText'))

6. 注意点

1.如果同一页面中某一属性有多个元素时,可以使用定位方法 下标来指定想要操作的元素,并且需要注意含有多个元素时要使用find_elements函数。

代码语言:javascript复制
# 定义输入框,画面中共有3个输入框
element = driver.find_elements(AppiumBy.CLASS_NAME('android.widget.EditText'))
# 指定第一个输入框中输入“张三”
element[0].send_keys("张三")

2.Android与iOS中元素定位的差异点在于,Android的元素如果不在当设备画面中,比如需要上划或者下划才(swipe)能看见的元素,需要先做对应操作让其展示出后才能进行元素的定位。而iOS则完全不需要如此操作;

3.即使是id也不会绝对唯一,因为在软件的版本迭代中可能会出现某些元素因业务需要被去掉但是新加的元素与老元素处在同一id属性的情况,一般来说如果脚本或框架出定位了id属性却出现NoSuchElementException就需要查看属性是否重复且选择了错误的元素。所以建议在定位元素前多用用Inspector中的元素搜索功能查看一下;

4.如果你是做iOS相关的APP自动化的话,尽量在元素定位的时候少用xpath方法来定位,即使是相对路径的方式也仍然会大大增加Appium的运行时间;

5.另外就是一个老生常谈的问题了,如果APP中某些元素是需要异步加载或执行的还是建议在定位元素之前加上等待时间,强制不太推荐,至于隐性还是显性的大家结合着自己的测试业务与被测对象看着来就行。

0 人点赞