前言
在进行移动自动化测试时,常常要求我们进行UI覆盖率的测试(通过编写脚本去操作元素)
哪么有些人可能会有疑问,说:我自己动动手指不是也比你写脚本来得快吗?
可是你想想,如果有20台手机,3个版本的测试应用以及30个脚本,那你要测1800次…如果你动动手指,估计会测到产生人生三大疑问:我是谁,我在哪,我在干嘛?
以下是我测试的环境:
电脑系统:Mac OS 12.6
手机系统:Smartisan Pro2 Android 7.1.1
脚本语言:java
Appium:1.8
假设打开这篇文章的已经知道启动模拟器或者手机去连接UI Automator Viewer了。
所谓定位,要秉持着快准狠的理念去写定位代码才能写出最高效的测试用例
下面我打算通过 “美团app” 来讲解定位方式
文章大纲
1.根据id来定位
安卓里定位的Id一般为resource-id
通过findElementById(“resource-id的值”)就能定位到元素了(前提是要请确保id的值在可看到的页面中是唯一的),比如我们想定位天气这个图标,我们选中可以看到id值为:com.sankuai.meituan:id/weather_stub。
我们可以看到这个id的命名还是很语义化的,很大几率可以肯定是唯一的,因此我们点击这个元素可以这样写
findElementById("com.sankuai.meituan:id/weather_stub").click();
如果id不是唯一的,那就无法点到,比如下图:
两家店铺的id都是相同的,如果还是用之前的方法,会定位到第一个符合条件的控件。因此是不行的,下面会讲到这种情况用XPath如何定位,见6.2
2.根据name定位
安卓里text属性认为是name
由于findElementByName在appium版本1.5后就被废除了,需要使用xpath来定位text属性,见6.1
3.根据content-desc来定位
安卓里content-desc属性认为是 AccessibilityId
因此可以通过如下代码查找控件并点击
driver.findElementByAccessibilityId("附近").click();
4.根据ClassName定位
安卓里的class属性认为是ClassName
driver.findElementByClassName("android.widget.ImageButton")
需要注意这种定位方式适用性不强,因为class的种类太少了,一个页面难免会有重复的,因此,要么你还能点击页面中的第一个这种classname,要么还是需要查找到该class的一个集合,然后通过下标去访问。
5.根据AndroidUiAutomator定位元素
AndroidUIAutomator是一个强有力的元素定位方式,它是通过Android UIAutomator类库去找元素
通过androidUIAutomator 又可以使用其中的 new UiSelector()…访问控件,例如:
-
className( 即class属性)
-
driver.findElementByAndroidUIAutomator("new UiSelector().className(\"android.widget.ImageButton\")");
-
-
description(即content-desc属性)
-
driver.findElementByAndroidUIAutomator("new UiSelector().description(\"美食\")")
-
-
resourceId(即resource-id属性)
-
driver.findElementByAndroidUIAutomator("new UiSelector().resourceId(\"com.sankuai.meituan:id/category\")");
-
-
text(即text属性)
-
driver.findElementByAndroidUIAutomator("new UiSelector().text(\"登录\")");
-
-
如果同时需要添加两个以上条件,可以这样写:
-
driver.findElementByAndroidUIAutomator("new UiSelector().text(\"登录\").resourceId(\"com.sankuai.meituan:id/category\")");
-
-
更多api可参考 UiSelector
6.根据xpath定位
虽然说xpah定位是万能的,几乎没有找不到的元素,但是建议能用以上的定位方式找到的控件,就尽量不用xpath,因为其查找效率会比较慢。
当元素具有唯一性
6.1 使用XPath根据text内容进行定位*
由于findElementByName在appium版本1.5后就被废除了,因此想通过text来定位元素需要使用:
driver.findElementByXPath("//*[@text='登录']").click();
//表示在当前可视的整个布局文件中搜索某个控件的text属性的值为登录的控件
或者更严谨一点:
driver.findElementByXPath("//android.widget.Button[@text='登录']").click();
//与上一行代码相比,多了一层限定条件,查找效率会高些吧~
或者你也可以只需模糊匹配即可:
driver.findElementByXPath("//android.widget.TextView[contains(@text,'登')]").click();
6.2 使用XPath根据resource-id定位
List<WebElement> elements = driver.findElementsByXPath("//android.widget.TextView[@resource-id='com.sankuai.meituan:id/poi_name']");
elements.get(1).click();//由于不是唯一的id,所以先将所有的id加到一个List中,这样表示点击了第二家店铺
当然,如果resource-id是唯一的,那也可以这样写:
driver.findElementByXPath("//android.widget.TextView[@resource-id='com.sankuai.meituan:id/poi_name']").click();
注意 findElementByXPath和findElementsByXPath的区别
6.3 使用xpath的绝对定位和相对定位
如果以上的定位方式都无法定位就要考虑使用绝对定位或者相对定位了
绝对定位就是从文档的根目录进行查找定位,例如我们要点击下图所示的店铺可以这么写:
driver.findElementByXPath("//android.widget.FrameLayout/android.widget.ListView[1]/android.widget.LinearLayout[2]").click(); //需要注意这里的xpath定位下标是从1开始的
相对定位就是先定位到一个比较容易定位到的元素,在相对于这个定位进行定位,比如,我想定位下面的优惠团购这个按钮
driver.findElementByXPath("//android.widget.TextView[@text='优惠团购']/parent::android.widget.LinearLayout").click();//先定位一段文字再定位它的父亲