1. 程式人生 > >Appium Android定位元素與操作

Appium Android定位元素與操作

一、常用識別元素的工具

uiautomator:Android SDK自帶的一個工具,在tools目錄下

monitor:Android SDK自帶的一個工具,在tools目錄下

Appium Inspector:Appium自帶的一個功能,只有mac下可以使用該功能

下面是用monitor抓取到的頁面元素

下面使用Appium Inspector定位的元素

二、元素定位

1.格式:find_element_by_定位方式(value)

通過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")

三、元素操作

找到元素後可以對元素進行的操作,例如上面講的進一步定位元素

1.click()

//點選操作

也可以用tab實現點選操作

driver.find_element_by_id("com.wuba.zhuanzhuan:id/ae8").click()

2.clear()

//清空輸入框內容

driver.find_element_by_id("com.wuba.zhuanzhuan:id/ij").clear()

3.send(xx)

//輸入框內輸入內容

driver.find_element_by_id("com.wuba.zhuanzhuan:id/ij").send_keys("test content")

4.text

//獲得元素的text內容

print(driver.find_element_by_xpath(" //android.widget.LinearLayout[1]//xxx").text)

四、觸控操作

1.driver.tap([座標],持續點選時間)

除了定位到元素的點選外,也可以通過tab實現座標的點選

driver.tap(driver.tap([(216,1776)],2))

2.TouchAction(driver)

TouchAction物件包含(tab)、press(短按)、move_to(滑動到某個座標)等方法

通過TouchAction物件,新增tap、move_to等操作,然後perform()執行,可以實現解鎖螢幕等功能

規範中的可用事件有:

 * 短按 (press)  * 釋放 (release)  * 移動到 (moveTo)  * 點選 (tap)  * 等待 (wait)  * 長按 (longPress)  * 取消 (cancel)

 * 執行 (perform)

例如:一個多次滑屏的例子:

from appium.webdriver.common.touch_action import TouchAction

action=TouchAction(driver)

action.press(x=220,y=700).move_to(x=840, y=700).move_to(x=220, y=1530).move_to(x=840, y=1530).release().perform()

可以通過wait()等待操作

3.MultiAction()//多點觸控

通過MultiAction().add()新增多個TouchAction操作,最後呼叫perform()一起執行這些操作

action0 = TouchAction().tap(el)

action1 = TouchAction().tap(el)

MultiAction().add(action0).add(action1).perform()

4.driver.swipe(x1, y1, x2, y2,duration)  

//從座標(x1,x2)滑動到座標(x2,y2),duration非必填項,滑動時間

(滑動的座標不能超過螢幕的寬高)

可以通過【driver.get_window_size()】命令獲得視窗高和寬,結果為{'width': 1080, 'height': 1776}

一個滑鼠向上下左右活動的例子如下:

#獲得螢幕大小寬和高 def getSize(driver):     x = driver.get_window_size()['width']     y = driver.get_window_size()['height']     return (x, y) #螢幕向上滑動 def swipeUp(driver,t=1000):     l = getSize(driver)     x1 = int(l[0] * 0.5)    #x座標     y1 = int(l[1] * 0.75)   #起始y座標     y2 = int(l[1] * 0.25)   #終點y座標     driver.swipe(x1, y1, x1, y2,t) #螢幕向下滑動 def swipeDown(driver,t=1000):     l = getSize(driver)     x1 = int(l[0] * 0.5)  #x座標     y1 = int(l[1] * 0.25)   #起始y座標     y2 = int(l[1] * 0.75)   #終點y座標     driver.swipe(x1, y1, x1, y2,t) #螢幕向左滑動 def swipLeft(driver,t):     l=getSize(driver)     x1=int(l[0]*0.75)     y1=int(l[1]*0.5)     x2=int(l[0]*0.05)     driver.swipe(x1,y1,x2,y1,t) #螢幕向右滑動 def swipRight(driver,t=1000):     l=getSize(driver)     x1=int(l[0]*0.05)     y1=int(l[1]*0.5)     x2=int(l[0]*0.75)

    driver.swipe(x1,y1,x2,y1,t)

#呼叫向下滑動的方法

swipeDown(driver)

五、系統按鍵事件

 press_keycode(AndroidKeyCode)//傳送按鍵事件

例如:點選home鍵,home鍵的KeyCode是3

driver.press_keycode(3)

鍵名                  描述       鍵值 KEYCODE_CALL        撥號鍵     5 KEYCODE_ENDCALL     掛機鍵     6 KEYCODE_HOME        按鍵Home      3 KEYCODE_MENU        選單鍵     82 KEYCODE_BACK        返回鍵     4 KEYCODE_SEARCH      搜尋鍵     84 KEYCODE_CAMERA      拍照鍵     27 KEYCODE_FOCUS       拍照對焦鍵   80 KEYCODE_POWER       電源鍵     26 KEYCODE_NOTIFICATION 通知鍵        83 KEYCODE_MUTE        話筒靜音鍵   91 KEYCODE_VOLUME_MUTE 揚聲器靜音鍵  164 KEYCODE_VOLUME_UP   音量增加鍵   24 KEYCODE_VOLUME_DOWN 音量減小鍵   25

更多KeyCode可以檢視下面的部落格:

http://blog.csdn.net/crisschan/article/details/50419963

六、driver的一些比較重要操作

1.reset()

//重置app

這時候driver會重置,相當於解除安裝重灌應用。所以本地快取會失效

driver.reset()

2.start_activity(包名,activity名)

//啟動app的某一個activity

例如:driver.start_activity("com.wuba.zhuanzhuan","./presentation.view.activity.LaunchActivity")

啟動一個activity,這個activity必須是AndroidManifest.xml中有intent-filter的activity

<intent-filter>

    <action android:name="android.intent.action.MAIN"/>

   <category android:name="android.intent.category.LAUNCHER"/>

</intent-filter>

這種啟動activity和driver的reset()不同的是

3.contexts

//獲得所有contexts

driver.contexts

結果如下:

['NATIVE_APP', 'WEBVIEW_com.android.browser']

NATIVE_APP:native的context

WEBVIEW_com.android.browser:webview的context,存放html的容器

4.current_context

//檢視當前的context

driver.current_context

5.switch_to.context(context名)

//切換context

driver.switch_to.context("WEBVIEW_com.wuba.zhuanzhuan")

NATIVE時不能定位WEBVIEW的內容,在WEBVIEW的context時不能定位NATIVE的內容。

所以需要切換到對應的context中去進行操作

6.setNetworkConnection(bitmask掩碼)

//設定網路型別

例如:設定網路型別為只開wifi

driver.set_network_connection(2)

網路的bitmask掩碼如下:

| 值 (別名)           | 資料連線 | Wifi 連線 | 飛航模式 |

| ------------------ | ---- | ---- | ------------- |

| 0 (什麼都沒有)       | 0    | 0    | 0 |

| 1 (飛航模式)         | 0    | 0    | 1 |

| 2 (只有Wifi)        | 0    | 1    | 0 |

| 4 (只有資料連線)     | 1    | 0    | 0 |

| 6 (開啟所有網路)     | 1    | 1    | 0 |

7.補充一些driver啟動時可能用到的項

其實這些在上一篇啟動裡都有介紹,但是有些可能大家沒注意到的點再列一下。這些點也是我在測試中實際遇到的點

autoLaunch :Appium是否要自動啟動或安裝app,預設true

desired_caps['autoLaunch'] = 'false'

有的時候我不想讓appium每次都啟動app,想自己去啟動activity,那這個項這時就可以起作用了

noReset:在會話前是否重置app狀態。預設是false

desired_caps['noReset'] = 'true'

newCommandTimeout:設定未接收到新命令的超時時間,預設60s

如果60s內沒有接收到新命令,appium會自動斷開連線,如果我需要很長時間做driver之外的操作,可能延長接收新命令的超時時間

desired_caps["newCommandTimeout"]=1800