Appium Appium 入门到原理之 Appium 根据 xpath 获取控件实例随笔

TechoGoGoGo · 2015年02月04日 · 最后由 江渤洋 回复于 2016年02月19日 · 2985 次阅读

如文章《Appium 基于安卓的各种 FindElement 的控件定位方法实践》所述,Appium 拥有众多获取控件的方法。其中一种就是根据控件所在页面的 XPATH 来定位控件。

本文就是尝试通过自己的试验来尝试对 Appium 如何用 xpath 来定位控件做一个阐述,当中如有不对的地方敬请大家指出。

背景

本文尝试使用的试验对象是 SDK 自带的 NotePad 应用实例,假设已经有两个 Notes 分别是 “note1” 和 “note2” 添加到 Notepad 上面,我们要做的就是尝试用 xpath 的方法来定位 “note2” 这个 ListView 下面的 TextView 控件。

注意界面上有 3 个 TextView 类型的控件:

  • 最上面的作为整个 ListView 的 Title 文本为 “Notes” 的 TextView,Index 为 0
  • 中间的文本为 “note2” 的 TextView,Index 也是 0
  • 最下面的文本为 “note1” 的 TextView,Index 是 1

xPath 获取控件方式

  • 通过判断控件属性获取控件

控件的所有属性都可以用作判断,比如:

* 通过文本查找目标控件

el = driver.findElementByXPath("//android.widget.TextView[contains(@text,'note2')]");
assertThat(el.getText(),equalTo("note2"));

* 通过 index 查找目标控件

如果我们像下面的方式使用 index 为 0 来查找控件 note2,那么将会失败,因为该 xpath 只是说 “我要查找页面上 android.widget.TextView 类型的 index 为 0 的控件 “,但如背景所说我们事实上有 3 个 TextView 控件,其中最上面的和中间的控件他们的 Index 都是 0.所以最终获得的控件其实是 Appium 第一个找到的最上面文本为” Notes“的 TextView。
el = driver.findElementByXPath("//android.widget.TextView[contains(@index,0)]");
assertThat(el.getText(),equalTo("note2"));
那么我们就要想办法加多点路径,让 xpath 能分辨出需要的是下面的 index 为 0 的 TextView,而不是上面的。观看上图的 UIAutomatorViewer 控件的分层结构,发现这两个 TextView 是从 LinearLayout 开始分叉的,所以我们应该从该路径开始通过数组下标指定我们需要的是” 在 LinearLayout 下面的第二个 FrameLayout 下面的 ListView 下面的 Index 为 0 的 TextView:

el = driver.findElementByXPath("//android.widget.LinearLayout[1]/android.widget.FrameLayout/android.widget.ListView/android.widget.TextView[contains(@index,0)]");
assertThat(el.getText(),equalTo("note2"));

* 通过其他属性查找目标控件
TBD,这些就不一一列举了,参照以上两个示例进行实现就可以了

  • 通过指定选择集合的位置获得控件

    按照我的实践和理解,通过这种方式获取控件是不靠谱的,起码存在两个问题。

    • 问题 1:控件在集合中的位置是不可控的。 el = driver.findElementByXPath("//android.widget.TextView[1]"); assertThat(el.getText(),equalTo("note2")); 以上的例子我原意是想把 UIAutomatorViewer 里面的上中下 3 个 TextView 中的中间那个给找出来,但结果返回来给我的确实最上面的那个 “Notes”。
    • 问题 2:通过增加路径层数限制查找指定元素集合不起效。 el = driver.findElementByXPath("//android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout/android.widget.ListView/android.widget.TextView[0]"); assertThat(el.getText(),equalTo("note2"));

    以上例子我本意是想通过增加父路径的限制来表明 “我想要的控件是 ListView 下面的那两个 TextView 控件中的第一个”,但返回给我的是 “An unknown server-side error occurred while processing the command",感觉是越界了的样子。

  • xpath 用法官方手册

    至于其他非主流获的通过 xpath 取控件的方式,请参考 xpath 官方手册中文版:http://wenku.baidu.com/link?url=tLdn9X4ucgmzYyKj4dpsgSDbshXEw6W8BTyqQAXd0kTMY6lBQqLiIL9FHtcZmdIeO8o5ZKV-fzlw96mFgvmWZ-qz35EPObyv8hKLTuyxbv3

作者:天地会珠海分舵
http://techgogogo.com
http://blog.csdn.net/zhubaitian

共收到 9 条回复 时间 点赞

很好的文章居然没人回复

#1 楼 @young
承蒙错爱

很不的分享啊

#3 楼 @oscar
这个回复很有艺术感哦,oscar 玩抽象主义艺术的吧?我在想那个 “不” 字后面应该填什么比较好呢?v^

#4 楼 @zhubaitian 哈哈,少打一个字,产生歧义。我是点赞的 O(∩_∩) O

#5 楼 @oscar
那这种抽象现实主义我喜欢。_^

挺好的,我还以为 el = driver.findElementByXPath("//android.widget.TextView[contains(@index,0)]") 这个会报错呢,因为 findelement 但实际上获取的是数组。学习了!

赞~~~!
我也加一个,同级别的 xpath 可以这样找。

driver.findElementByXPath("//android.widget.TextView[contains(@text,‘appium’)]/../android.widget.button") 

同级别的弟弟 Element 还可以这样写。

driver.findElementByXPath("//android.widget.TextView[contains(@text,‘appium’)]/following::sibling/android.widget.button")

这是抄的吧,原文还有图片呢

恒温 Appium 入门到原理合集 中提及了此贴 03月16日 08:33
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册