Python 测开27期 - julia - 学习笔记 - APP自动化高级定位技巧

高阶定位-Xpath

包含-contains()

  • Xpath 表达式中的一个函数
  • contains()函数匹配==属性值==中包含的==字符串==
//*[contains(@属性,"属性值")]
  • contains() 函数定位的元素很容易为 list
  • contains() 函数内的属性名需要用 @开始

XPath 轴

  • 父子

    • 当前节点的父节点
      //*[@text="HK"]/..
      //*[@text="HK"]/parent::*
    • 当前节点的儿子节点
      //*[@resource-id="com.xueqiu.android:id/stock_layout"]/child::*
  • 爷孙

    • 当前节点的父级的父级
      //*[@text="HK"]/../.. //*[@text="HK"]/parent::*/parent::*
    • 当前节点的儿子的儿子
      //*[@resource-id="com.xueqiu.android:id/stock_layout"]/child::*/child::*
  • 祖先

    • 返回当前节点的所有祖先
      //*[@text="HK"]/ancestor::android.widget.RelativeLayout
    • 显式指定要返回的祖先
      //*[@text="HK"]/ancestor::android.widget.RelativeLayout[1]
      RelativeLayout[1] 1是距离最近的一个,数值越大离得越远,1是父节点,2是爷爷节点。。。
  • 兄弟姐妹

    • 节点后的兄弟姐妹节点following-sibling
      • 选择当前节点之后的所有兄弟节点
      • 节点后有一个兄弟节点
        //*[@text="HK"]/following-sibling::*
      • 节点后有多个兄弟节点
        //*[@resource-id="com.xueqiu.android:id/stock_layout"]/following-sibling::*[@resource-id="com.xueqiu.android:id/price_layout"]
    • 节点前的兄弟姐妹节点 preceding-sibling
      • 选择当前节点之前的所有兄弟节点
      • 节点前有一个兄弟节点
        //*[@text="09988"]/preceding-sibling::*
      • 节点前有多个兄弟节点
        //*[@resource-id="com.xueqiu.android:id/add_attention"]/preceding-sibling::*[@resource-id="com.xueqiu.android:id/price_layout"]

XPath 运算符

AND

  • 可以在 XPath 表达式中放置 2 个条件
  • AND 两个条件都应该为真的情况下,才能找到元素
//*[@resource-id="com.xueqiu.android:id/current_price" and @text="107.8"]

OR

  • 可以在 XPath 表达式中放置 2 个条件
  • OR 的情况下,两个条件中的任何一个为真,就可找到元素。
  • OR 定位获取的是并集
//*[@resource-id="com.xueqiu.android:id/tv_stock_add_follow" or @text="加自选"]

高阶定位-CSS

css selector 定位介绍

  • 官网说明
  • Android: Appium Server 版本 >= 1.19.0
    css selector will be converted to -android uiautomator selector in UIAutomator2.
  • iOS:Appium Server>= 1.21.0
    css selector selector will be converted to -ios class chain selector

css selector 用法

# 通过 id
elementById("someResourceID")`
    -> `elementsByCss("#someResourceID")
# 通过 class
elementsByClassName("android.widget.TextView")`
    -> `elementsByCss("android.widget.TextView")
# 通过 accessibility id
elementsByAccessibilityId("Some Content Description")`
    -> `elementsByCss('*[description="Some Content Description"]')
# 通过 xpath
elementsByXpath("//android.widget.TextView[@description='Accessibility']")`
    -> `elementsByCss("android.widget.TextView[description='Accessibility']")

示例

  • 打开【雪球】应用首页
  • 点击搜索框
  • 向搜索框输入:alibaba
  • 判断【阿里巴巴】可见
def test_search1(self):
    # 点击搜索框
    element = self.driver.find_element(\
        AppiumBy.CSS_SELECTOR,"#com\.xueqiu\.android\:id\/tv_search")
    element.click()
    # 向搜索框输入:alibaba
    self.driver.find_element(AppiumBy.CSS_SELECTOR,
        "#com\.xueqiu\.android\:id\/search_input_text"). \
        send_keys("alibaba")
    alibaba_element = self.driver.find_element(\
        AppiumBy.CSS_SELECTOR, "*[text='阿里巴巴']")
    displayed = alibaba_element.get_attribute("displayed")
    print(displayed)
    # 判断【阿里巴巴】可见
    assert displayed == "true"
    print(f"结束时间:{self.get_time()}")

iOS css selector 定位

Toast 识别

Toast 是什么

  • 一种消息框类型
  • 永远不会获得焦点
    • 无法被点击
  • Toast显示的时间有限,Toast会根据用户设置的显示时间后自动消失
  • 是系统级别的控件,属于系统settings
  • Toast类的思想:
    • 就是尽可能不引人注意,同时还向用户显示信息,希望他们看到

Toast 定位

  • appium 用的是uiautomator底层来抓取toast,
  • 再把toast放到控件树内,但是它本身不属于空间
  • 使用的是uiautomator2

Toast 定位

  • xpath 可以找到
    //[@class=“android.widget.Toast”]//[contains(@text,“xxx”)]
    xxx:toast的文本内容
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(50));  
driver.findElement(AppiumBy.xpath("//*[@class=\"android.widget.Toast\"]"));

显示等待

  • 显示等待是客户端的等待
  • WebDriverWait(self.driver, 10).until(expected_conditions.visibility_of_element_located(Locator))
  • 用到的两个类:WebDriverWait和expected_conditions
  • 显示等待可以等待动态加载的ajax元素,显示等待需要使用ExpectedConditions来检查条件

  • 一般页面上元素的呈现
    • title出现 首先出现title
    • dom树出现 presense,还不完整
    • css出现 (可见visibility)
    • js出现, js特效执行(可点击clickable)
  • HTML文件是至上而下加载的
  • js 文件加载会阻塞html内容的加载,有些js异步加载的方式来完成js加载
  • 样式表下载完成之后会跟之前的样式表一起进行解析,会对之前的元素重新渲染

使用lambda表达式

  • WebDriverWait(driver,time).until(lambda x: x.find_element_by_id(someid)) 返回一个元素

总结三种等待方法

  • 隐式等待,尽量默认都加上,时间限定在3-6秒,不要太长,为了所有的find_element方法都有一个很好的缓存
  • 显示等待,用来处理隐式等待无法解决的一些问题,比如:文件上传(可以设置长一点),文件上传需要设置20s以上,但是如果设置隐式等待,它会在每个find方法都等这么长时间,一旦发现没有找到元素,就会等20s以后才抛出异常,影响case的执行效率,这时候就需要用显示等待,显示等待可以设置的长一点
  • 强制等待: 一般不推荐,前两种基本等解决绝大部分问题,如果某个空间没有任何特征,只能强制等待,这种情况比较少