自動化測試來說,核心技能就是對象的定位。不管是 web 頁面上的一個
按鈕或輸入框,還是移動 app 上的一個按鈕或輸框,我們要想對其進行點選或輸入操作,前提是要先找到這個對象。對于手工測試來說,是由測試人員來完人了,人通過眼睛與大腦來識别一個按鈕或輸入框,但自動測試工具沒有這種能力,但是一個對象一定會有一些屬性(如 id、class 等),自動化測試工具就是靠着這些屬性來識别和查找對象。webdriver 提供了八種元素定位方法:
l id
l name
l class name
l tag name
l link text
l partial link text
l xpath
l css selector
在 Python 語言中對應的定位方法如下:
find_element_by_id()
find_element_by_name()
find_element_by_class_name()
find_element_by_tag_name()
find_element_by_link_text()
find_element_by_partial_link_text()
find_element_by_xpath()
find_element_by_css_selector()
一組元素定位的方法如下:
find_elements_by_id()
find_elements_by_name()
find_elements_by_class_name()
find_elements_by_tag_name()
find_elements_by_link_text()
find_elements_by_partial_link_text()
find_elements_by_xpath()
find_elements_by_css_selector()
Appium 完全繼承了 WebDriver 中所定義的這些方法,除此之外對其進行了擴充,以便适合移動端對象的定位與操作
定位的工具
uiautomatorviewer:Android SDK自帶的一個工具,在tools目錄下
monitor:Android SDK自帶的一個工具,在tools目錄下
Appium Inspector:Appium自帶的一個功能,隻有mac下可以使用該功能
定位詳解
通過id定位
(取resource-id的值):
driver.find_element_by_id("com.wuba.zhuanzhuan:id/azo")
也可以直接用id後面的内容driver.find_element_by_id("azo")
通過class_name定位
(取class的内容)
driver.find_element_by_class_name("android.widget.RelativeLayout")
通過xpath定位
(取xpath得内容)
driver.find_element_by_xpath("//android.widget.LinearLayout[1]/android.widget.XXX")
通過text定位
(需要使用uiautomator的定位方式,使用text的内容)
driver.find_elements_by_android_uiautomator("new UiSelector().text(\"+關注\")")
使用這裡需要注意一下,通過text定位的結果是個list,不能直接click。是以如果要點選需要取數組的值,比如下面是點選找到的第一個元素
driver.find_elements_by_android_uiautomator("new UiSelector().text(\"+關注\")")[0].click()
通過css_selector定位(webview)
隻适用于webview的html頁面,繼承自webdriver,與pc版本的UI測試一緻
driver.find_element_by_css_selector()
通過link_text定位(webview)
隻适用于webview容器中的html頁面,繼承自webdriver,與pc版本的UI測試一緻
driver.find_element_by_link_text()
通過name定位
web view容器中的html頁面可以用name定位,native并沒有name屬性
driver.find_element_by_name()
2.定位元素的另一種寫法:find_element(by,value)
find_element_by_方式(value)實際調用的都是find_element(by,value)
需要導入這個包:from selenium.webdriver.common.by import By
例如:定位id為ag2的元素
方式一:driver.find_element_by_id("ag2”)
方式二:driver.find_element(By.ID,"ag2")
這個操作的好處是可以直接把操作的by和value放到一個元組裡,然後調用通用方法來傳參獲得元素結果
cateid=(By.ID,"ag2")
driver.find_element(*cateid).click()
by的操作可以是:
By.ID 相當于by_id
By.CLASS_NAME 相當于by_class_name
By.XPATH 相當于by_xpath
By.NAME 相當于by_name
By.TAG_NAME 相當于by_tag_name
By.CSS_SELECTOR 相當于by_css_selector
By.LINK_TEXT 相當于by_link_text
3.find_elements_by_定位方式(value)傳回元素數組
用法與find_element_by_方式(value)一緻,但是傳回一個數組。可以通過數組的索引來通路具體的某個結果
例如:通過class_name定位到多個元素,我想點選第一個元素
driver.find_elements_by_class_name("android.widget.RelativeLayout”)[0].click()
4.傳回元素數組的另一種寫法:find_elements(by,value)
用法與find_element(by,value)一緻,但是傳回一個數組。可以通過數組的索引來通路具體的某個結果
例如:通過class_name定位到多個元素,我想點選第一個元素
driver.find_elements(By.CLASS_NAME,"android.widget.RelativeLayout”)[0].click()
5.通過元素定位元素
可以先找到某個元素,然後再進一步定位元素
find_element_by_class_xpath(“xxx”).find_element_by_name(“yyy")
UiSelector
概述:
按照一定的條件(例如控件的text值,資源id),定位界面上的元素。UiSelector對象的最終目的是去構造一個UiObject對象。
摘要:
1、根據text構造:
函數傳回值 | 函數體 | 說明 | 用法 |
UiSelector | text(String text) | 根據“控件text屬性的内容”構造出UiSelector對象 | 例如,一個控件text的值是“發現”,UiSelector s = new UiSelector().text("發現"); |
UiSelector | textContains(String text) | 根據“控件text屬性包含的内容”構造出UiSelector對象 | 同上例子:UiSelector s = new UiSelector().textContains("現"); |
UiSelector | textMatches(String regex) | 根據“控件text屬性正規表達式的内容”構造出UiSelector對象 | 正規表達式文法參考網上資料即可。 |
UiSelector | textStartsWith(String text) | 根據“控件text屬性開始的内容”構造出UiSelector對象 | 同上例子:UiSelector s = new UiSelector().textStartsWith("發"); |
比較常用,準确度也比較高,中文查找的時候,如果遇到 “UiOjbectNotFoundException” 的時候,記得把項目的編碼格式改為utf-8。
2、根據description構造:
UiSelector | description(String desc) | 根據“控件content-desc屬性的内容”構造出UiSelector對象 |
UiSelector | descriptionContains(String desc) | 包含** |
UiSelector | descriptionMatches(String regex) | 正則 |
UiSelector | descriptionStartsWith(String desc) | 以**開始 |
同text的用法基本一緻,也是比較靠譜的一種方式。
3、根據資源id:
UiSelector | resourceId(String id) | 根據資源id擷取對象,例如:UiSelector s = new UiSelector().resourceId("com.tencent.mm:id/b8m") |
UiSelector | resourceIdMatches(String regex) | 根據資源id的正規表達式擷取對象 |
4、根據類:
UiSelector className(String className):
根據控件的類名來找到UiSelector對象。
但是呢?因為一般Android布局的時候,同樣的控件類名都是一樣的。
是以我在微信的登入界面調用: UiSelector s = new UiSelector().className("android.widget.TextView") 這句話,它得到的就是我左上開始算第一個class名稱為“android.widget.TextView”的控件。
UiSelector instance (int instance):
上面提到的假如我們想擷取螢幕上電話号碼的那個TextView使用這樣方法,就可以使用instance:
UiSelector s = new UiSelector().className("android.widget.TextView").instance(1);
UiSelector index(int index):
用法和上面的instance差不多,谷歌的原文說這個方法是unreliable的,推薦使用instance方法。
UiSelector childSelector(UiSelector selector):
有的時候假如子控件不好獲得,而其父控件比較好獲得的時候,我們通常采用這樣的方式,例如下面:
我們目前選中的是LinearLayout,這個Android中的一種布局,它的裡面嵌套了兩個控件,一個是ImageView,另一個是EditText。這們這裡就通過LinearLayout這個控件找到它的子控件。
很明顯,父控件id已經給定。我們先得到父控件:UiSelector s_p = new UiSelector().resourceId("com.tencent.mm:id/axj");
其次 UiSelector s_c= s_p.childSelector( new UiSelector().className("android.widget.EditText") );
在它的父控件的childSelector方法中傳入一個帶有一定特征的UiSelector對象,即可得到子控件,這裡 s_c 就是輸入框的UiSelector對象。
UiSelector fromParent(UiSelector selector):
有的時候父控件也不好獲得,而是同級的控件(同屬一個parent)比較好擷取,那麼使用這樣方法,還拿上面的舉例:
我們先得到EditText的UiSelector對象:UiSelector s1 = new UiSelector().resourceId("com.tencent.mm:id/axc");
得到和它同樣一個父控件的ImageView的UiSelector對象:UiSelector s2 = fromParent( new UiSelector().className("android.widget.ImageView") );
5、根據特有屬性:
UiSelector | checked(boolean val) | 根據是否可check來構造出UiSelector對象 |
UiSelector | chickable(boolean val) | |
UiSelector | enabled(boolean val) | |
UiSelector | focusable(boolean val) | |
UiSelector | longClickable(boolean val) | |
UiSelector | scrollable(boolean val) | |
UiSelector | selected(boolean val) |
舉個簡單的例如,假如目前的界面,隻有一個checkbox是勾選狀态,你就可以這樣得到:UiSelector s2 = new UiSelector().checked(true)