Appium+python自动化3-定位元素
3.1常用定位方法讲解
对象定位是自动化测试中很关键的一步,也可以说是最关键的一步,毕竟你对象都没定位那么你想操作也不行。所以本章节的知识我希望大家多动手去操作,不要仅仅只是书本上的知识,毕竟这个我只能够举例说明。下面我们来看我们常用的一些定位方式
find_element_by_id()
find_element_by_name() #appium较新版本name定位被去掉
find_element_by_class_name()
find_element_by_xpath()
项目使用的工具是uiautomatorviewer,在安卓sdk的tools目录下(C:\Program Files (x86)\Android\androidSDK\tools,查看环境搭建章节)
3.1.1 ID定位
无论是在web自动化还是app自动化中id都是唯一的
面图片中左边部分用红色圈出来的对象的id我们在右边的属性中可以看到,他的id我同样是用红色圈出,如果我们需要对“点击相机,搜你所见”这个输入框进行输入信息,我们只需操作右边的id就行,下面我们直接看代码
#!/usr/bin/env python # -*- codinfg:utf-8 -*- ''' @author: Jeff LEE @file: 启动百度.py @time: 2018-07-25 15:24 @desc: ''' import time from appium import webdriver desired_caps={ 'platformName':'Android', 'deviceName':'D3F021C19001219', #手机设备名称,通过adb devices查看 'platformVersion':'4.4', #android系统的版本号 'unicodeKeyboard':'True', 'resetKeyboard':'True', 'appPackage':'com.baidu.searchbox',#apk包名 'appActivity':'com.baidu.searchbox.SplashActivity', #apk的launcherActivity } driver=webdriver.Remote('http://localhost:4723/wd/hub',desired_caps) time.sleep(5) # 点击“输入框” driver.find_element_by_id("com.baidu.searchbox:id/baidu_searchbox").click() time.sleep(3) # 输入字段 searchInputBox = driver.find_element_by_id('com.baidu.searchbox:id/SearchTextInput') searchInputBox.send_keys("Appium") time.sleep(3) driver.quit()
通过上面的代码我们能够直接在输入框中输入Appium,如下图所示
3.1.2 className定位
在实际工作中className定位用得相对而言会比较少。当你经常去看class时你会发现很多的className是一样的,你没有办法对其进行唯一定位,下面我们看下面两张图片
通过className定位的代码
driver.find_element_by_class_name('android.widget.TextView')
这种方式去定位,你会发现你永远定位不了‘appium原理’,这是为什么呢?因为在设计的时候如果你查找的元素在页面有多个,系统会自动给你选择第一个,所以你永远操作不了后面的,那如何解决这种问题呢?我们看后面讲解。
3.1.3 xpath定位
xpath定位在web自动化中是最常见的,而且也是最有效的,使用xpath定位避免了找不到元素导致报错的问题,但是在app中使用xpath定位是一件很low的事情。为什么这么说呢?因为在作者的经历中只要遇见使用xpath定位元素他的反应就会比较慢,自动化的目的是为了提高效率,但是使用xpath后会降低效率,所以这里说很 low。
通过xpath定位的代码
driver.find_element_by_xpath('//android.widget.TextView[@text="appium原理"]').click()
运行结果
在xpath里面我们的语法是这样'//android.widget.TextView[@text="appium原理"]',这个和我们之前web的xpath一样,意思是查找所有节点中节点为android.widget.TextView (这里使用的是text,也可以使用id或class等元素,系统会依次去找)并且他的text属性值为appium原理,这样是否更容易理解呢?下来多练习。这样的定位方式不推荐,效率很慢。
3.2 层级定位
3.2.1 概念
在前面的章节中我们已经提到了层级定位,只是不知道具体怎么操作而已。在很多的自动化中如果只是靠简单的定位是没有办法完成自动化的,就像刚xpath定位一样,有的元素的id、className都是一样的,xpath定位效率低下,这个时候我们大多数都会采用层级定位。
3.2.2 项目中层级定位如何运用
从上面的图片我们可以看出id为android.widget.TabWidget的节点下面包含了很多的android.widget.FrameLayout
从这张图片我们不难看出,如果我们要定位这个元素我们是没办法去定位的,这种情况我们大多数使用的是层级定位以及xpath,这里我们来看如何使用层级定位。
首先我们可以看出两幅图的结构上的区别,第二幅图元素他是在第一幅图里面的,这里我们称第一幅图id为android:id/tabs的节点为第二幅图元素的父节点,我们只需要先通过id定位到父节点,然后再从父节点往下面进行定位第二幅图就可以了
elemet =driver.find_element_by_id('android:id/tabs') elemet.find_element_by_class_name('android.widget.FrameLayout').click()
运行会你会发现不报错,可也不会点击,这个是为什么呢?因为在父节点下的所有子节点他的className都是“android.widget.FrameLayout”,这种情况下他怎么去点击操作呢?所以在这种情况下会引发一个新的定位问题,就是我们接下来要讲的List定位
3.3 List定位
List故名思义就是一个列表,那么他的个数也就成了不确定性,所以这里需要用复数,所以在我们定位时我们不能够接着用find_element_by_id等等定位方式了,我们需要用他的复数形式find_elements_by_id,所有的定位方式都一样需要采用复数加s。
以上面例子为例,我要点击‘好看视频’,代码如下:
elemet =driver.find_element_by_id('android:id/tabs') elemets=elemet.find_elements_by_class_name('android.widget.FrameLayout') elemets[1].click()
运行结果如下:
3.4 内嵌H5定位
在web自动化中我们会遇见frame的问题,在遇见这些内嵌的标签后我们需要做的就是切换窗口,那么在app自动化测试也有类似的情况就是我们经常看见的内嵌html,在我们原生的app中增加一个由html做成的页面
后续补充,只要在测试之前加这个代码即可
#获取当前页面所有的contexts webview = driver.contexts #在获取到的contexts list里面去挨个循环 for context in webview: #判断循环中单个的context是否是webview,如果是就进行切换,并且跳出循环 if 'WEBVIEW' in context: driver.switch_to.context(context) break
3.5 滑动定位
3.5.1 滑动定位方式
在app自动化中我们经常会遇见一个问题,我们需要查找的元素不在当前可展示的屏幕,至于在什么地方我们不知道,如果这个时候我们一直使用在当前页面查找,那么系统就会报错,为了解决这个问题我们就需要使用滑动查找。
首先的思路是我们在需要查找对象的页面查找一下该元素,判断该元素是否在当前页面,如果该元素不在该页面那么我们就需要去互动屏幕,到我们的下一屏幕,然后再进行查找,依次类推到找到为止。
3.5.2 滑动定位思路分析
方式我们有了,那么我们就需要知道实现这个功能应该有哪些点。下面跟着我一起来分析一下:
1、需要查找的元素我们是不是需要知道是什么呢?这个需要先确定
2、我们需要找的页面是在我们的当前页面的上方还是下方还是左方还是右方,我们不能确定,那么我们是否需要确定我们需要滑动的方向?
3、元素和方向有了,但是你知道我们每次需要滑动屏幕的多少吗?那么我们是否需要先去获取屏幕的大小,然后针对不同的方向去计算一个滑动的值呢?
3.5.3 滑动定位实战
class BaseOperate(object): def __init__(self,driver): self.driver =driver self.get_size() def get_size(self): self.width = self.driver.get_window_size()['width'] self.height = self.driver.get_window_size()['height'] def swipe_left(self,t): self.driver.swipe(self.width*9/10,self.height/2,self.width/10,self.height/2,t) self.screenshot() def swipe_right(self,t): self.driver.swipe(self.width/10,self.height/2,self.width*9/10,self.height/2,t) self.screenshot() def swipe_up(self,t): self.driver.swipe(self.width/2,self.height*9/10,self.width/2,self.height/10,t) self.screenshot() def swipe_down(self,t): self.driver.swipe(self.width/2,self.height/5,self.width/2,self.height*9/10,t) self.screenshot() def findLocal(self): x = 1 while x==1: if self.fact() == 1: self.swipe_up(2000) time.sleep(3) self.fact() else: print ("找到了") x=2 def fact(self): n =1 try: self.driver.find_element_by_id('cn.com.open.mooc:id/tv_replace').click() except Exception,e: return n