0中使用Xpath定位元素

题外话

这段日子翻新有一点延迟哈,这是因为接了一个外包项指标活(便是活动端自动化相关的),忙的“外黑里焦”的,幸好应该2个礼拜的拼命已经步入尾期,项目总体效应都曾经落到实处,前面有空给大家享用,明日的焦点是讲一下在应用进程中相见的三个难题,如何在UiAutomator2.0中运用Xpath定位成分?

(1)获取当前页面包车型客车activity名,比如: (.ui.login.ViewPage)

背景

于今的app在打包成apk的时候都以有加强管理的,种种混淆加固,所以已经毁损了或忧虑了本来的代码变量命名情势,那就给大家要基于分界面来做自动化测量试验带来了悲凉的阻止,因为那一个混淆过的id是不定点的,下壹遍再出个新本子,那整个都变了,所以那就不可能用id来恒定混淆过的app成分,那还或许有何好的秘籍吗?还记得Web自动化测量检验中神乎其技的xpath吗?不管如何因素都可以用它稳固出来,所以自身就想在UiAutomator2.0中也选拔它来恒定混淆的app成分,那要怎么样操作?UiAutomator2.0的API中并未交到xpath这种措施,那大家不得不和谐去写一个了。

图片 1 current_activity()

思路

参照他事他说加以考察UI Automator Viewer中抓取到的组织档次,无法用resource-id,又要显示出等级次序关系,那就只可以是class属性了,这里的class能够对应web xpath中的标签,使用产业界统一的斜杠/来维持档案的次序,那么最原始状态下的xpath大概就是其一样子了:

android.view.ViewGroup/android.widget.ImageView再加上下标android.view.ViewGroup[2]/android.widget.ImageView[0]

图片 2xpath的格式定义出来了之后,我们就开端一层一层去遍历,比非常的粗略通过斜杠/来分隔出一个class数组,然后逐个去搜求那些class对应的成分,通过老爹和儿子关系拼接起来,直到最终四个class,存在就赶回对应的对象,不设有就再次回到null。出于岁月涉及,这一遍就是初探,只兑现了这种绝对路线下的原则性,其实要想完全达成这么些职能,还索要帮忙相对路线的向来,以及各个品质的结合定位,其实基于那几个本子上边改改也不远了,那就留给风乐趣的童鞋去实现吗。

 比方大家需求实现这些登陆的功效时,重要思路为假如当前分界面为记名页面时,就进行登陆行为,否则就跳转到登陆页面。其伪代码为:

实现

1、首先要兑现基于class或任何属性去找到某些成分的子成分,笔者那边达成了支持传入种种参数,代码如下:

public static UiObject2 getChild(Object root, Map<String,String> params) { if (params == null || !params.containsKey { log.e("[Error]参数错误: 为空或未包含[class]key"); return null; } String clazz = params.get; String className = clazz; int index = 0; if (clazz.endsWith && clazz.contains { //有下标 className = clazz.substring(0, clazz.lastIndexOf; String num = clazz.substring(clazz.lastIndexOf + 1, clazz.lastIndexOf; index = num != null && !"".equals ? Integer.parseInt : index; } List<UiObject2> childList = null; if (root instanceof UiObject2) { childList = ((UiObject2) root).getChildren(); } else { childList = hasObjects(By.clazz(className)) ? mDevice.findObjects(By.clazz(className)) : null; } List<UiObject2> tempList = new ArrayList<UiObject2>(); if (childList != null && !childList.isEmpty { for (UiObject2 child : childList) { boolean isMatch = child.getClassName().equals(className); if (params.containsKey { isMatch = isMatch && child.getApplicationPackage().equals(params.get; } if (params.containsKey { isMatch = isMatch && child.getText().equals(params.get; } if (params.containsKey { isMatch = isMatch && child.getContentDescription().equals(params.get; } if  { tempList.add; } } } if(tempList.isEmpty { return null; } if (index >= tempList.size { log.e(String.format("[Error]查找class[%s] 下标[%d]越界[%d]", clazz, index, tempList.size; return null; } return tempList.get; }

2、再写三个因此class获取子元素的简短完成,因为这种艺术用的多:

 public static UiObject2 getChild(Object root, String clazz) { Map<String,String> params = new HashMap<String,String>(); params.put("class", clazz); return getChild(root, params); }

3、插手解析xpath表明式的一些,将深入分析和寻找整个经过连起来:

public static UiObject2 findObjectByXpath(UiObject2 root, String xpath) { if (xpath == null && "".equals { log.e("[Error]xpath expression[" + xpath + "] is invalid"); return null; } String[] xpaths = null; if (xpath.contains { xpaths = xpath.split; } else { xpaths = new String[]{xpath}; } UiObject2 preNode = root; for (String path : xpaths) { preNode = getChild(preNode, path); if (preNode == null) { //log.e(String.format("按xpath[%s]查找元素失败, 未找到class[%s]对应的节点", xpath, path)); break; } } return preNode; }

4、使用演示:

String commentXpath = "android.widget.LinearLayout/android.widget.LinearLayout/android.widget.TextView[0]";UiObject2 commentView = findObjectByXpath(root, commentXpath);
1 if driver.current_activity == ".ui.login.ViewPage":
2     // To login_action
3 else:
4     // Trun to loginPage

总结

既是是初探就先写这么多啊,给个达成思路,如若把全路职能都造成,能够虚构开源到github上有助于恒河沙数别的U2自动化的童鞋,前濒有时光能够思虑一下,小编更愿意有童鞋主动来促成(哈哈,不做测验了,没在此以前那么大的热忱和生机来搞这一个了)。

原稿来自下方大伙儿号,转发请联系笔者,并必须保留出处。想第不平日间看见更加多原创手艺好文和材质,请关怀公众号:测量试验开垦栈

 

(2)获取当前页面的树形结构源代码,与uiautomatorviewer截屏所展现出来的布局是平等的

图片 3 page_source()

比如当大家做到报到流程之后,要看清登入是或不是中标,则足以肯定登入后的页面有未有出现一定的从头到尾的经过(例如:运动圈、发掘、运动、商铺、小编的),其伪代码达成如下:

图片 4

图片 5

driver  
    .page_source.find(u"运动圈") != -1 and 
    .page_source.find(u"发现") != -1 and 
    .page_source.find(u"运动") != -1 and 
    .page_source.find(u"商城") != -1 and
    .page_source.find(u"我的") != -1 and

图片 6

图片 7

page_source()的回来数据类型为str。python中,str的find(context)方法,假设str存在context再次来到值为context在str的index,借使一纸空文,则重返值为-1。由此只需求决断以上代码块再次回到的布尔值是True or False,就足以判明是不是登陆成功。

 

(3)获取到近些日子窗口的具有context的名目

图片 8 contexts()

 在native和html5混合页面测量检验时,须要在native层和H5层切换,所以率先须求获得context层级的称呼

print driver.contexts


>>> ['NATIVE_APP', 'WEBVIEW_com.codoon.gps']

有鉴于此,大家知道App的H5层名字为"WEBVIEW_com.codoon.gps"后,使用driver.switch_to.context("WEBVIEW_com.codoon.gps")就可以完结NATIVE和H5层的切换了。

 

二、获取控件类API

(1)通过成分id查找当前页面包车型客车二个指标成分

图片 9 find_element_by_id()

 通过源码注释能够收获find_element_by_id这一类的api首要有八个应用渠道:

driver.find_element_by_id("com.codoon.gps:id/tv_login")  // from webdriver.py

在driver下通过id查找二个成分,此用法经常适用于当下分界面包车型地铁driver有且唯有多少个独一的id成分标示,通过调用find_element_by_id能够标准到找到对象成分;另一种接纳路子主要如下:

图片 10

图片 11

driver_element = driver.find_element_by_xpath("//android.widget.ListView/android.widget.LinearLayout")

 

// from webdriverelement.py

driver_element.find_element_by_id("com.codoon.gps:id/activity_active_state") 

图片 12

图片 13

在driver.find_element_by_xpath返回了driverElement类型,调用find_element_by_id在driverElement下的子元素以id相称目的成分。

图片 14

上图为uiautomatorviewer对id,name,class的图示表明。非常表达:若id、name、xpath等在此时此刻driver也许driverElement查找的目的成分不是独一成分,此时调用find_element_by_id(namexpath)时,会回来搜索相配到的首先个因素。

 

(2)通过成分id查找当前页面包车型客车三个目的元素

图片 15 find_elements_by_id()

在driver下通过id查找四个指标成分,其归来值类型为list。此用法平日适用于当下driver下查询listView、LinearLayout、 RelativeLayout等有雷同布局结构的Item;同样除了driver之外,在driverElement下页能够跳用find_elements_by_id来匹配listView、LinearLayout、 RelativeLayout。

driver.find_elements_by_id("com.codoon.gps:id/tv_name")  // from webdriver.py

driver.find_element_by_id("com.codoon.gps:id/webbase_btn_share")  
  .find_elements_by_id("com.codoon.gps:id/ll_layout")  // from driverelement.py

Tips: 带有find_elements关键字的艺术函数的回来类型都以list数据类型,独有driver与driverelement的实例化有find_element(s)等一三种措施,list类型是不能够用find_element(s)方法定位数据的。在骨子里的连串中恐怕会遇见那样的主题素材,唯有遍历list,收取每七个element实例化对象再张开查找定位成分。

 

(3) 通过成分name查找当前页面包车型地铁一个要素

图片 16 find_element_by_name()

应用办法与find_element_by_id同样,只是把相称原则由id变为name。请参照他事他说加以考察find_element_by_id的调用方式

driver.find_element_by_name("foo")
driver.find_element_by_id("com.codoon.gps:id/tv_name").find_element_by_name("foo")


>>> return the driverElement(obj)

 

(4) 通过成分name查找当前页面包车型客车三个指标成分

图片 17 find_elements_by_name()

使用办法与find_elements_by_id一样,只是把相配原则由id变为name。请参谋find_elements_by_id的调用格局,注意其再次来到数据类型是List,而不是driverElement。

driver.find_elements_by_name("foo")
driver.find_element_by_id("com.codoon.gps:id/tv_name").find_elements_by_name("foo")

###  return the List<driverElement>
>>> ['driverElement1', 'driverElement2', 'driverElement3', ....]

 

(5)通过成分xpath查找当前页面包车型大巴三个目的成分

图片 18 find_element_by_xpath()

关于find_element_by_xpath的调用方法与经过id、name略有分裂,有关Xpath的连带知识点在本章节一时不表,后续在档案的次序实施中若有供给再另起专项论题介绍。

driver.find_element_by_xpath("//android.widget.TextView[contains(@text, '开始')]")
driver.find_element_by_xpath("//android.widget.LinearLayout/android.widget.TextView")

在Appium中,xpath所需相关的lib库并从未完全帮忙,所以选用办法是上述三种(即仅支持在driver下的xpath相称)。近些日子的Appium版本不能够支撑driverelement下的xpath查找,如

driver.find_element_by_xpath("//android.widget.LinearLayout/android.widget.TextView")  
.find_element_by_xpath("//android.widget.TextView[contains(@text, '开始')]")             // This is the Error!

 按上边的写法Appium就能够报错,原因是“.find_element_by_xpath("//android.widget.TextView[contains(@text, '开始')]")”不能够在Element下查找子成分。

 

(6) 通过成分xpath查找当前页面包车型大巴八个目标成分

图片 19 find_elements_by_xpath()

 参照find_element_by_xpath的调用方式,需注意再次来到类型为List,用法参谋find_elements_by_name()的例子

 

(7) 通过元素class name查找当前页面包车型大巴的三个要素

图片 20 find_element_by_class_name()

在实际项目中,测验app中class name并不可能做为分界面包车型地铁不二法门标示定位,所以在骨子里中差十分的少从不应用class name在driver查看成分,在driverelement下查找子成分用class name才是合情合理的施用方法。

 

(8) 通过成分accessibility_id (content-desc)查找当前页面的多少个要素

图片 21 find_element_by_accessibility_id()

在uiautomatorviewer中,content-desc内容即为accessibility_id,在seleniumCurry能够用find_element_by_name()来相配content-desc的剧情;在AppiumCurry则用find_element_by_accessibility_id()来相配content-desc的剧情。因为Appium承袭了Selenium类,所以若是find_element_by_name不恐怕精确定位时,请试试看find_element_by_accessibility_id。

   常用的收获控件类API正是上述这么些。别的的查找和十分的api还也可能有find_element_by_link_text、find_elements_by_link_text、find_element_by_tag_name、find_elements_by_tag_name、find_element_by_css_selector、find_elements_by_css_selector等,用法都与上述类似。

 

三、成分操作类API

   大家在完成PC端浏览器Webdriver自动化时,对于网页上的靶子的操作首要有:点击(click)、 双击(double_click)、滚动(scroll)、输入(send_keys),而运动端特有的援助类api:轻击(tap)--扶助多点触控,滑动(swipe),放大成分(pinch),缩短成分(zoom)

(1)点击事件 

图片 22 click()

图片 23 tap()

click和tap都能促成单击的功效。其不相同在于click是法力于driverelement的实例化对象,而tap是对显示屏上的坐标地方进行点击。前面二个对成分的地点变动并不敏感,而后面一个是针对实际的像素坐标点击,受分辨率和因素地点影响十分大。

 

(2)输入事件

图片 24 send_keys()

图片 25 set_text()

 send_keys和set_text也都能知足输入文本内容的操作。其分别在于send_keys会调用设备当前系统输入法键盘,而set_text直接对指标成分设置文本。由此可推,send_keys的输入内容往往和预期内容差别样,而set_text的输入则是平素赋值,并不是键盘事件。

 

(3)滑动(翻屏)事件

图片 26 swipe() 

图片 27 flick()

swipe和flick都是滑动操作,它们都以从[start_x, start_y]划到[end_x, end_y]的进度,唯一分化的是swipe比flick多了三个duration参数,有了这一个参数就足以自定义从start到end动作的法力时间,以完成神速滑动或然慢速度滑冰动的功效。

 

(4)缩放事件

图片 28 pinch()

图片 29 zoom()

暗许会对目的成分进行推广一倍也许缩短四分之二的操作,此api方法符合于在测量试验活动地图的缩放时的转移。

 

(5)长按事件

图片 30 long_press()

长按章程是在TouchAction类中,所以在利用时索要先import TouchAction。在剔除运动历史记录时,在记录列表长按删除,

action1 = TouchAction(self.driver)
driver_element = driver.find_element_by_xpath("sport_history_item_xpath")

action1.long_press(driver_element).wait(i * 1000).perform()   // i为长按控件的时间,单位秒

 

(6)keyevent事件(android only)

  在Android keyevent事件中,区别的值代表了分歧的意思和效应,比方手提式有线电话机的重回键:keyevent(4); 手提式有线电电话机的HOME键: keyevent(3)等等,具体keyevent与对应值关系请仿效 

 

四、成分事件类API

(1) reset

图片 31 reset()

用法:driver.reset(),重新初始化应用(类似删除应用数据),如第三次登陆app时出现的指导页,则足以用reset来落成供给。

 

(2) is_app_installed

图片 32 is_app_installed()

检查app是不是有安装 再次来到 True or False。举个例子:在微信登入时,选取登入情势时会剖断是还是不是已安装微信,若未设置则有dialog弹框,已安装则跳转到微信登入页面,

driver.find_element_by_id("weixin_login_button").click()
if driver.is_app_installed("weixin.apk"):
    // To do input User, Passwd
else:
    // show dialog

 

(3)install_app

图片 33 install_app()

接上个例子,若未安装微信出现dialog弹框,检查完dialog后再安装微信app。特不要表明:例子中的"weixin.apk"是指app_path + package_name,

图片 34

图片 35

driver.find_element_by_id("weixin_login_button").click()
if driver.is_app_installed("weixin.apk"):
    // To do input User, Passwd
else:
    check_dialog()
    driver.install_app("weixin.apk") 

图片 36

图片 37

 

(4) remove_app

图片 38 remove_app()

在测量检验老版本宽容用例时,用老版本替换新本未时,要求卸载新本子,再安装老版本,所以需求调用到此措施,

driver.remove_app("new_app.apk")  # 卸载
driver.install_app("old_app.apk") # 安装

 

(5) launch_app

图片 39 launch_app()

开发一个capabilities配置的设施选用。此情势方今并不曾应用。待以后用到时再来做立异。

 

(6) close_app

图片 40 close_app()

 关闭app应用程序。此方法常用在代码末尾,在清理和假释对象时选择。结合unittest框架常见tearDown()里应用,

图片 41

图片 42

import unittest

class demo(unittest.TestCase):
    def setUp(self):
        pass

    def tearDown(self):
        driver.close_app()
        driver.quit()

图片 43

图片 44

 

(7) start_activity

图片 45 start_activity()

此方法适用于测量检验中需利用八个及以上的app程序。比如,在运动相关的测量试验时,首先供给开采Gps模拟照应工具,初始照拂。然后打开咕咚接纳运动项目开首活动,那么能够在起步capabilities配置时打开Gps工具,开启配速照望后再展开咕咚app,

图片 46

图片 47

driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps={'platformName': 'Android',
                        'deviceName': 'Android Mechine',
                        'appPackage': ' Package of GpsTools',
                        'unicodeKeyboard':True,
                        'resetKeyboard':True,
                        'noReset':True,
                        'appActivity': 'activity of GpsTools'})

# TO DO Gps Mock action

driver.start_activity("com.codoon.gps", "ui.login.welcomeActivity")

图片 48

图片 49

  

(8) wait_activity

图片 50 wait_activity()

此办法适属于appium等待方法的一种。不论是webdriver照旧appium,等待方法分为三种类型:显式等待、隐式等待,time.sleep;从wait_activity的源码可以看来,是属于隐式等待。有关等待格局以往能够另开专项论题详细表明,这里不做赘述。

  此情势首要选取在须要网络加载时的守候,比方在顾客登入作为前提条件时,wait_activity接受三个参数: 供给静观其变加载的activity的名目,timeout超时时刻(秒),检验间隔时间(秒),

driver.login_action()
driver.wait_activity("homepage.activity", 30, 1)
driver.find_element_by_id("我的").click()

其含义是,等待加载app的homepage的activity出现,等待最长日子30秒,每隔1秒检查测验二遍当前的activity是不是等于homepage的activity。假如,则推出等待,试行点击自身的tab的action;若否,则持续等待,30秒后提示超时抛出非常。

 

四、其余(此种类下第一对上述未有涉及的api方法的增加补充)

(1) 截屏

图片 51 get_screenshot_as_file()

用法:driver.get_screenshot_as_file('../screenshot/foo.png'),接受参数为保存的图纸路线和称号

 

(2)size 和 location

图片 52 size()

图片 53 location()

size 和 location是对element地点和尺寸的取得,那五个天性首要利用在有可划动的控件,如完善个人资料页,出生之日、身体高度和体重都急需划动。之前大家提到的swipe和flick是指向设备显示屏进行划动,分明在那边不适用。何况未有三个特定的措施,所以需求大家友好针对可划动控件实行划动,

图片 54 swipe_control()

 

(3)获取控件各样品质

图片 55 View Code

用法: driver.find_element_by_id().get_attribute(name),name就是左侧的标识(class,package,checkable,checked....),重回值为str类型,即就是true or false,可是事实上是"true" or "false"

 图片 56

 

(4)pull_file

图片 57 pull_file()

将设备上的公文pull到本地硬盘上,在手提式有线电话机号注册时索要取得手机验证码,此时的落实际意况势是用另多个apk提取到验证码存在手提式有线电话机内部存款和储蓄器中,再用pull_file获取到验证码内容,使得appium可以将正确的验证码填入。

  

  本章节Appium常用的有的API函数,日后有亟待会日渐地举办填空。就算不能够左右逢源,但在实际上项目中提到到的都早已大半提到了。当大家对某些意义实行测验的时候,首先要对其打开操作,那个时候将要思虑到找到相应的目的成分,调用具体的平地风波类函数,验证结果的时候,大家要检查测量检验操作发生的结果是否与大家预料的一律?那这就要去思考相应的Assert函数(即断言)了。所以记住那六字箴言:对象-事件-断言,便能够使您能够动手对其它三个App编写对应的自动化测量检验用例了。

 

本文由365bet体育在线官网发布于网络编程,转载请注明出处:0中使用Xpath定位元素

TAG标签:
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。