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
