Time will tell.
元素定位是自动化测试中关键的一步,因为你对象都没定位好,那么你想去操作这也是行不通的,所以本章节也是希望同学们多去动手实战,不要仅仅只是看过、看了。
一、 常用定位
1、ID定位
无论是在 web 自动化还是 app 自动化中id
都是唯一的,那为什么有的地方说name
定位是唯一的呢,在这里又为什么是id
呢?
其实这个不冲突,但如果你用 appium 较新版本那是不行的,在新版本中 name
定位被去掉了,所以在以后的定位中都不会有name
定位了。
看到这里可能又有小伙伴会有疑问,有的时候你的应用为什么没有id
,或者说在这个手机上有但在另外的手机上却没有?
原因:
- 开发没有添加
- android 版本是4.4以下的
图中左边部分用红色圈出来的对象的id
,我们在右边的属性中可以看到,它的id
同样用红色圈出,如果我们需要对 “请输入淘宝账户” 这个输入框进行输入信息,只需操作右边的 id 就行,看代码:
driver.find_element_by_id("com.taobao.taobao:id/aliuser_login_account_et").send_keys("aaa")
2、className定位
在实际工作中className
定位用得相对而言会比较少。当你经常去看 class 时你会发现很多的className
是一样的,你没有办法对其进行唯一定位,下面我们看两张图:
可以看一下这两张图片中淘宝账号、密码两个输入框中的className
都是一样的,如果在这种情况下你使用下边这种方式去定位,你会发现你永远定位不了密码栏,这是为什么呢?
因为在设计的时候如果你查找的元素在页面有多个,系统会自动给你选择第一个,所以你永远操作不了后面的,那么在实际工作或实战中遇到此类问题如何解决?后面会讲到。
driver.find_element_by_class_name("android.widget.EditText").send_keys("aaa")
3、xpath定位
xpath
定位在 web 自动化中是最常见的,而且也是最有效的,使用xpath
定位避免了找不到元素导致报错的问题,但是在 app 中使用xpath
定位是一件很low的事情。为什么?
因为在过来人的经历中,只要遇到使用xpath
定位元素,它的反应就会比较慢,自动化的目的是为了提高效率,但使用xpath
后会降低效率,所以这里说有点low。但很多时候不得不去了解,下面我们首先要熟悉一下 web 的xpath
定位。
讲 web 的xpath
之前大家先装一下 fireFox 浏览器,再在浏览器中安装fireBug
以及FirePath
两个插件。如下:
在自动化或学习xpath
时这两个插件是必不可少的,这里我们直接讲xpath
,来看下面一张图片理解:
用红色圈出有虚线的输入框我们看一下FirePath
给我们的定位,在定位的xpath
中显示的是:
py “.//*[@id='kw']”
这个是什么意思呢?我们一步一步说。
1、//* 选取文档中的所有元素
2、@id=‘kw’] 匹配属性为 id 且值为 kw 的节点。
这里可能有小伙伴不是很理解,说这里直接使用 id 进行定位就行。其实也是,但是当没有这个属性的时候呢?我们看下面这张图:
name
定位无效的情况下,当你看到这张图片的时候如果你不用xpath
怎么定位呢?有一些抓狂的感觉吧。小伙伴可以尝试着自己使用xpath
进行定位,可能有一些人发现xpath
中定位不是很明白了,为什么呢?
.//*[@id='u1']/a[4]
在这个xpath中我们没有像之前那样思路清晰了他多了一些层级关系,这个后面我们会仔细讲。这个xpath中首先第一步:
1、@id='u1’和之前的一样匹配属性为id值为ul的节点,然后再在他的下面进行定位第二步
2、/a[4] 意思就是从根节点下选取第四个a元素。
这样一步一步解析是否更加容易理解了呢?下面我们看一下在xpath定位中经常用到的一些语法:
这个是我们经常用到的,而且是最基础的知识,只有这些没有办法完成很多古怪的需求,那么就有更难的,下面我们看下面的列表:
这些在:http://www.w3school.com.cn/xpath/xpath_examples.asp 当中可以看得到,大家也可以多看多练习一下。
下面我们直接看在 app 中 xpath 的使用
上面两张图片中,我们能看见它们的id
、className
都是一样的,这样的情况下不用层级定位方式,我们只能够采用xpath
来进行定位,根据前面 web 的学习大家可以思考一下该怎么定位。直接看代码:
driver.find_element_by_xpath("//android.widget.TextView[@text='聚划算']").click()
在 xpath 里面我们的语法是这样 “//android.widget.TextView[@text=‘JavaScript’]”,这个和我们之前webxpath
一样,意思是查找所有节点中节点为android.widget.TextView
。这里使用的是className
,也可以使用id
,系统会依次去找。并且它的text
属性值为JavaScript
,这样是否更容易理解呢?这样的定位方式不是很推荐,效率较慢。
2 、层级定位
在前面我们已经提到过层级定位,只是不知道具体怎么操作。在很多自动化中如果只是靠简单的定位是没有办法完成自动化的,就像刚xpath
定位一样,有的元素的id
、name
、className
都是一样的,xpath
定位效率低下,这个时候我们大多数都会采用层级定位。
那么,在项目中层级定位如何运用呢?下面我们来看一个简单的例子理解层级定位。
从上面的图中我们可以看出id
为com.taobao.taobao:id/rv_main_container
的节点下面包含了很多的android.widget.FrameLayout
。
从下面的图片我们可以看出id
为android.widget.FrameLayout
的节点下面包含了很多的android.widget.LinearLayout
。
这张图片我们不难看出,如果要定位这个元素是没办法去定位的,这种情况我们大多数使用的是层级定位以及xpath
,这里我们来看如何使用层级定位。
首先我们可以看出3张图结构上的区别,第3张图的元素它是在第2张图里面的,第2张图元素它是在第1张图里面的。
这里我们称第1张图id(com.taobao.taobao:id/rv_main_container)
为android.widget.FrameLayout
的节点为第2张图元素的父节点,第2张图id(android.widget.FrameLayout)
为android.widget.FrameLayout
的节点为第3张图元素的父节点,第1张图id(com.taobao.taobao:id/rv_main_container)
为android.widget.LinearLayout
的节点为第3张图元素的祖父节点,我们只需先通过id
定位到祖父节点,然后再从祖父节点往下面依次进行定位就好。现在你可以练一练,看看结果一样吗?看代码:
1 element= driver.find_element_by_id("com.taobao.taobao:id/rv_main_container")
2 element1 = element.driver.find_elements_by_class_name("android.widget.FrameLayout")
3 element2 = element1[1].find_element_by_class_name("android.widget.LinearLayout")
4 element2.click()
按照思维我们的代码会是上面的结果,但是你去运行会发现不报错,可也不会点击,这是为什么呢?我们看下面的图片:
在祖父节点下的所有子节点它的className
都是 “android.widget.FrameLayout” ,在父节点下的所有子节点它的className
都是 “android.widget.LinearLayout” ,这种情况下它怎么去点击操作呢?所以在这种情况下会引发一个新的定位问题,就是接下来要讲的List
定位。
参考代码:
# coding=utf-8
# 1.先设置编码,utf-8可支持中英文,如上,一般放在第一行
# 2.注释:包括记录创建时间,创建人,项目名称。
# 3.导入模块
from appium import webdriver
import time
desired_caps = {}
desired_caps['platformName'] = 'Android' #android的apk还是IOS的ipa
desired_caps['platformVersion'] = '8.0' #android系统的版本号
esired_caps['deviceName'] = '127.0.0.1:62001' #手机设备名称,通过adb devices 查看
desired_caps['appPackage'] = 'com.taobao.taobao' #apk的包名
desired_caps['appActivity'] = 'com.taobao.tao.welcome.Welcome' #apk的launcherActivity
# desired_caps['unicodeKeyboard'] = True #使用unicodeKeyboard的编码方式来发送字符串
# desired_caps['resetKeyboard'] = True #将键盘给隐藏起来
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps) #启动服务器地址,后面跟的是手机信息
# 休眠五秒等待页面加载完成
time.sleep(5)
element= driver.find_element_by_id("com.taobao.taobao:id/rv_main_container")
element1 = element.find_elements_by_class_name("android.widget.FrameLayout")
element2 = element1[1].find_element_by_class_name("android.widget.LinearLayout")
element2.click()
# driver.quit()
OK,以上就到这里喽,如果你对Python自动化软件测试更多内容感兴趣可以加入我们扣裙一起学习175317069。有各项测试学习资源发放,更有行业深潜多年的技术人分析讲解。
最后希望看到这里的你终成为一名极具竞争力的高级测试工程师。
觉得还不错就【点赞】、【评论】、【关注】吧~
Time will tell.(时间会说明一切)