1. 程式人生 > >Appium+python自動化(二十四)- 白素貞千年等一回許仙 - 元素等待(超詳解)

Appium+python自動化(二十四)- 白素貞千年等一回許仙 - 元素等待(超詳解)

簡介  

  許仙小時候最喜歡吃又甜又軟的湯圓了,一次一顆湯圓落入西湖,被一條小白蛇銜走了。十幾年後,一位身著白衣、有青衣丫鬟相伴的美麗女子與許仙相識了,她叫白娘子。白娘子聰明又善良,兩個人很快走到了一起。靠著自己的力量,他們過上了幸福的生活。一天,僧人法海找到許仙,警告說白娘子是一條修行千年的蛇精,許仙不信。到了端午節,勉強喝下了雄黃酒的白娘子現了原形,許仙被嚇得昏死過去。原來白娘子真的是之前吃下許仙湯圓的小蛇。白娘子辛苦救回了許仙的性命,但之後法海卻以保護許仙的名義將他囚禁起來,白娘子與小青召集蝦兵蟹將,要逼法海放出許仙。突然一座寶塔從天而降,把白娘子鎮在了塔下……  想必小夥伴和童鞋們都聽過,或者是看過這個故事,是多麼的痴情感人,尤其是千年等一回的歌曲是一個經典音樂。好了廢話還是少說,進入今天的主題--元素等待

  前邊介紹了APP頁面元素的識別定位、操作等技術,可能你會覺得掌握這兩項技術就可以實施APP自動化了,答案基本是這樣的,畢竟元素定位和操作是核心技術。但是,在某些場景,指令碼的執行並非預期那樣,如,要操作的元素用常規方法無法識別、元素可以識別但在指令碼執行時卻未如期而至等。為了解決這些疑難雜症,接下來內容將會介紹處理這些問題的通用方法。
  在本節,主要介紹元素等待的使用方法和場景,該方法是開發穩定、高容錯性自動化指令碼的前提。

思考

  在自動化過程中,元素出現受網路環境,裝置效能等多種因素影響。因此元素載入的時間可能不一致,從而會導致元素無法定位超時報錯,但是實際上元素是正常載入了的,只是出現時間晚一點而已。那麼如何解決這個問題呢?

實際測試過程中,比如點選一個控制元件需要啟動一個新activiy介面,或需要載入彈框,或請求網路載入資料成功後重新整理介面,此時需要等待一段時間,新介面出現了才能繼續執行UI操作,否則還在載入中,程式已開始執行新介面操作的程式碼,指令碼就會報錯了。

元素等待作用

1.設定元素等待可以更加靈活的制定等待定位元素的時間,從而增強指令碼的健壯性,提高執行效率。

2.元素等待是為了解決如下場景的問題:指令碼執行時,指令碼的執行速度和頁面元素的載入速度未必一致,也就是說,可能出現指令碼已經執行到某個元素,但該元素尚未載入到頁面,此時指令碼會因無法定位到該元素而導致執行失敗。元素等待本質是為了解決時序上不匹配的問題。

元素等待型別

型別 特點 舉例
強制等待

設定固定的等待時間

from time import sleep
#強制等待5秒
sleep(5)

隱式等待

針對全部元素設定的等待時間

driver.implicitly_wait(5)

顯示等待

針對某個元素來設定的等待時間

from selenium.webdriver.support.ui import WebDriverWait

WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None)

強制等待

  這種方法的等待,就相當於白素貞到西湖去等待許仙去,不管許仙是否出現,都要痴情地從白天等到晚上。說白了這種就是白素貞站在西湖那裡一動不動地死等許仙出現。純粹一個傻子!!!

設定固定的等待時間,使用sleep()方法即可實現

sleep(): 設定固定休眠時間。 python 的 time 包提供了休眠方法 sleep() , 匯入 time包後就可以使用 sleep()進行指令碼的執行過程進行休眠。

1 from time import sleep
2 
3 #強制等待5秒
4 
5 sleep(5)

隱式等待

隱式等待是針對全部元素設定的等待時間

  這種方法的等待,就相當於白素貞到西湖去等待許仙去,白素貞到了西湖先看看許仙在不在,一看在,白素貞完了再看看小青妹妹來沒來,等小青這個電燈泡來了,再去和許仙匯合。

 1 #implicitly_wait():是 webdirver 提供的一個超時等待。隱的等待一個元素被發現,或一個命令完成。如果超出了設定時間的則丟擲異常。
 2 #implicitly_wait():隱式等待
 3 #當使用了隱士等待執行測試的時候,如果 WebDriver沒有在 DOM中找到元素,將繼續等待,超出設定時間後則丟擲找不到元素的異常
 4 #換句話說,當查詢元素或元素並沒有立即出現的時候,隱式等待將等待一段時間再查詢 DOM,預設的時間是0
 5 #一旦設定了隱式等待,則它存在整個 WebDriver 物件例項的宣告週期中,隱式的等到會讓一個正常響應的應用的測試變慢,
 6 #它將會在尋找每個元素的時候都進行等待,這樣會增加整個測試執行的時間。
 7 
 8 #implicitly_wait()方法比 sleep() 更加智慧,後者只能選擇一個固定的時間的等待,前者可以在一個時間範圍內智慧的等待。
 9 
10 driver.implicitly_wait(20)

顯式等待

顯式等待是針對某個元素來設定的等待時間。

  這種方法的等待,就相當於白素貞到西湖去等待許仙去,白素貞到了西湖先看看許仙在不在,一看不在,白素貞自己先去做個頭發;過一個小時了,白素貞回來到西湖再去看許仙在不在,一看還是不在,再去買件衣服去;過一個小時了,白素貞回來到西湖再去看許仙在不在,一看仍然不在,再去買個包包去;過一個小時了,白素貞回來到西湖再去看許仙在不在,一看還是不在,白素貞鬱悶了,出去喝個小酒去;過了一小時了。。。。。。就這麼來來回回的折騰的等許仙。這個白素貞通過修煉進化變得聰明瞭。

WebDriverWait():同樣也是 webdirver 提供的方法。在設定時間內,預設每隔一段時間檢測一次當前。頁面元素是否存在,如果超過設定時間檢測不到則丟擲異常。

方法WebDriverWait格式引數如下:

 1 '''詳細格式如下:
 2 WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None)
 3 driver - WebDriver 的驅動程式(Ie, Firefox, Chrome 或遠端)
 4 timeout - 最長超時時間,預設以秒為單位
 5 poll_frequency - 休眠時間的間隔(步長)時間,預設為 0.5 秒
 6 ignored_exceptions - 超時後的異常資訊,預設情況下拋 NoSuchElementException 異常。
 7 WebDriverWai()一般由 until()或 until_not()方法配合使用,下面是 until()和 until_not()方法的說明。
 8 until(method, message=’’)
 9 呼叫該方法提供的驅動程式作為一個引數,直到返回值不為 False。
10 until_not(method, message=’’)
11 呼叫該方法提供的驅動程式作為一個引數,直到返回值為 False。
12 lambda
13 lambda 提供了一個執行時動態建立函式的方法。'''
14 
15 from selenium.webdriver.support.ui import WebDriverWait
16 
17 WebDriverWait(driver,10).until(lambda x:x.find_element_by_id("elementID"))

其中,三種等待方法的作用和區別,如下:

強制等待,也就是常說的死等待,使用time模組提供的sleep方法,指令碼在等待sleep(x) x秒後才執行,此時指令碼也許出現了無效等待,即元素已經出現,可以繼續操作,但因指定的時間未到,指令碼無法執行,因而,在實際Web UI開發中應杜絕sleep等待;

顯式等待,WebDriver提供的針對元素級別的、靈活、智慧的等待方法,通過配合until()、until_not()、ExpectedCondition等條件的使用,預設每500ms檢查一次條件狀態,可以及時將指令碼從等待中喚醒,避免無效等待,在實際應用中推薦使用該方法。

該等待的呼叫方法如下:

WebDriverWait(driver, 超時時長, 呼叫頻率, 忽略異常).until(可執行方法, 超時時返回的資訊)

隱式等待,WebDriver提供的針對driver級別的適用整個生命週期的等待方法,該等待是全域性設定,因而只需在例項化driver後設置一次即可。從等待作用上看,是可以滿足需要的,但是考慮到實際應用場景,driver要等待的元素和指令碼要操作的元素未必相同,也就是說,指令碼要操作的元素已經出現,但因為設定了全域性等待,driver也會繼續等待頁面上其他無關元素,直至整個頁面載入完畢。因而,與顯式等待相比,可能出現無效等待的情況。

等待方法實戰舉例

1.強制等待方法應用例項

 1 # coding=utf-8
 2 # 1.先設定編碼,utf-8可支援中英文,如上,一般放在第一行
 3 
 4 # 2.註釋:包括記錄建立時間,建立人,專案名稱。
 5 '''
 6 Created on 2019-7-26
 7 @author: 北京-巨集哥   QQ交流群:707699217
 8 Project:學習和使用appium自動化測試-元素等待
 9 '''
10 # 3.匯入模組
11 from appium import webdriver
12 import time
13 desired_caps = {}
14 desired_caps['platformName'] = 'Android'   #android的apk還是IOS的ipa
15 desired_caps['platformVersion'] = '8.0'  #android系統的版本號
16 desired_caps['deviceName'] = '127.0.0.1:62001'    #手機裝置名稱,通過adb devices  檢視
17 desired_caps['appPackage'] = 'com.taobao.taobao'  #apk的包名
18 desired_caps['appActivity'] = 'com.taobao.tao.welcome.Welcome'  #apk的launcherActivity
19 desired_caps['unicodeKeyboard'] = True   #使用unicodeKeyboard的編碼方式來發送字串
20 desired_caps['resetKeyboard'] = True   #將鍵盤給隱藏起來
21 driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps) #啟動伺服器地址,後面跟的是手機資訊
22 # 休眠五秒等待頁面載入完成
23 time.sleep(5)   #強制等待5s,不管等待的元素是否出現,都要等5s
24 driver.find_element_by_id("com.taobao.taobao:id/home_searchedit").click()
25 time.sleep(3)  #演示效果
26 driver.find_element_by_id("com.taobao.taobao:id/searchEdit").click()
27 driver.find_element_by_id("com.taobao.taobao:id/searchEdit").send_keys(u"北京-巨集哥")
28 driver.quit()

2.顯示等待方法應用例項

 1 # coding=utf-8
 2 # 1.先設定編碼,utf-8可支援中英文,如上,一般放在第一行
 3 
 4 # 2.註釋:包括記錄建立時間,建立人,專案名稱。
 5 '''
 6 Created on 2019-7-26
 7 @author: 北京-巨集哥   QQ交流群:707699217
 8 Project:學習和使用appium自動化測試-元素等待
 9 '''
10 # 3.匯入模組
11 from appium import webdriver
12 from selenium.webdriver.support.ui import WebDriverWait
13 import time
14 desired_caps = {}
15 desired_caps['platformName'] = 'Android'   #android的apk還是IOS的ipa
16 desired_caps['platformVersion'] = '8.0'  #android系統的版本號
17 desired_caps['deviceName'] = '127.0.0.1:62001'    #手機裝置名稱,通過adb devices  檢視
18 desired_caps['appPackage'] = 'com.taobao.taobao'  #apk的包名
19 desired_caps['appActivity'] = 'com.taobao.tao.welcome.Welcome'  #apk的launcherActivity
20 desired_caps['unicodeKeyboard'] = True   #使用unicodeKeyboard的編碼方式來發送字串
21 desired_caps['resetKeyboard'] = True   #將鍵盤給隱藏起來
22 driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps) #啟動伺服器地址,後面跟的是手機資訊
23 try:
24     # 顯示等待(等待特定元素出現)
25     WebDriverWait(driver, 3).until(lambda x: x.find_element_by_id('com.taobao.taobao:id/home_searchedit'))
26     driver.find_element_by_id("com.taobao.taobao:id/home_searchedit").click()
27     time.sleep(3)  # 演示效果
28     driver.find_element_by_id("com.taobao.taobao:id/searchEdit").click()
29     driver.find_element_by_id("com.taobao.taobao:id/searchEdit").send_keys(u"北京-巨集哥")
30 finally:
31     driver.quit()

3.隱式等待方法應用例項

 1 # coding=utf-8
 2 # 1.先設定編碼,utf-8可支援中英文,如上,一般放在第一行
 3 
 4 # 2.註釋:包括記錄建立時間,建立人,專案名稱。
 5 '''
 6 Created on 2019-7-26
 7 @author: 北京-巨集哥   QQ交流群:707699217
 8 Project:學習和使用appium自動化測試-元素等待
 9 '''
10 # 3.匯入模組
11 from appium import webdriver
12 from selenium.webdriver.support.ui import WebDriverWait
13 import time
14 desired_caps = {}
15 desired_caps['platformName'] = 'Android'   #android的apk還是IOS的ipa
16 desired_caps['platformVersion'] = '8.0'  #android系統的版本號
17 desired_caps['deviceName'] = '127.0.0.1:62001'    #手機裝置名稱,通過adb devices  檢視
18 desired_caps['appPackage'] = 'com.taobao.taobao'  #apk的包名
19 desired_caps['appActivity'] = 'com.taobao.tao.welcome.Welcome'  #apk的launcherActivity
20 desired_caps['unicodeKeyboard'] = True   #使用unicodeKeyboard的編碼方式來發送字串
21 desired_caps['resetKeyboard'] = True   #將鍵盤給隱藏起來
22 driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps) #啟動伺服器地址,後面跟的是手機資訊
23 
24 # 隱式等待(等待所有元素)
25 driver.implicitly_wait(3)  #隱式等待,最長3s
26 driver.find_element_by_id("com.taobao.taobao:id/home_searchedit").click()
27 time.sleep(3)  #演示效果
28 driver.find_element_by_id("com.taobao.taobao:id/searchEdit").click()
29 driver.find_element_by_id("com.taobao.taobao:id/searchEdit").send_keys(u"北京-巨集哥")
30 driver.quit()

小結

1.本節主要介紹appium自動化中三種元素等待方法,並講解了各自的優缺點,實際開發中推薦使用顯示等待,最後,為了便於理解和應用,針對每種等待方法,編寫了對應的指令碼。

2.強制等待的方法,在debug時候很有用,不過建議慎用這種方法,因為太死板,嚴重影響程式執行速度!

3.以上三種等待方法,在具體的場景中需要根據情況選擇合適的方法,靈活運用。。。

4.做過自動化的小夥伴們或者童鞋們,在啟動app的時候,幸運的小夥伴和同學們都會中這個大獎:如果直接做下一步點選操作,經常會報錯,於是我們便會自然而然的想到上邊介紹的三種方法,會在啟動完成的時候加sleep等方法。那麼問題來了,巨集哥問你這個sleep時間到底設定多少合適呢?你不知道巨集哥也不知道這個問題的答案,如果設定長了,就浪費時間,設定短了,就會找不到元素報錯了。過長過短都是個讓你頭疼的事,那麼有沒有別的方法可以克服這個問題了。當然有,巨集哥一般人都不告訴他,大家都是二般人,就分享給各位吧!但是這個只是針對安卓手機的哦,要記住了,iPhone不適合的。這個時候我們可以用wait_activity的語法,等到你想點選的頁面activity出現了,再點選,可以有效的節省時間。

wait_activity

(1)檢視原始碼

 1 def wait_activity(self, activity, timeout, interval=1):
 2     """Wait for an activity: block until target activity presents
 3     or time out.
 4     
 5     This is an Android-only method.
 6 
 7     :Agrs:
 8      - activity - target activity
 9      - timeout - max wait time, in seconds
10      - interval - sleep interval between retries, in seconds
11     """
12     try:
13         WebDriverWait(self, timeout, interval).until(
14             lambda d: d.current_activity == activity)
15         return True
16     except TimeoutException:
17         return False

(2)解釋說明:

 1 wait_activity(self, activity, timeout, interval=1):
 2 
 3     等待指定的activity出現直到超時,interval為掃描間隔1秒
 4 
 5     即每隔幾秒獲取一次當前的activity
 6     
 7     android特有的
 8 
 9     返回的True 或 False
10 
11     :Agrs:
12 
13      - activity - 需等待的目標 activity
14 
15      - timeout - 最大超時時間,單位是s
16 
17      - interval - 迴圈查詢時間
18 
19     用法:driver.wait_activity(‘.activity.xxx’,5,2)

獲取current_activity

(1)開啟app後,先sleep10秒,等app完全啟動完成進入主頁面,然後獲取當前介面的activity

 1 # coding=utf-8
 2 # 1.先設定編碼,utf-8可支援中英文,如上,一般放在第一行
 3 
 4 # 2.註釋:包括記錄建立時間,建立人,專案名稱。
 5 '''
 6 Created on 2019-7-26
 7 @author: 北京-巨集哥   QQ交流群:707699217
 8 Project:學習和使用appium自動化測試-元素等待
 9 '''
10 # 3.匯入模組
11 from appium import webdriver
12 from time import sleep
13 desired_caps = {
14                 'platformName': 'Android',
15                 'deviceName': '127.0.0.1:62001',
16                 'platformVersion': '4.4.2',
17                 'appPackage': 'com.baidu.yuedu',
18                 'appActivity': 'com.baidu.yuedu.splash.SplashActivity'
19                 }
20 driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
21 
22 sleep(10)
23 # 獲取當前介面activity
24 ac = driver.current_activity
25 print(ac)

(2)執行結果:

等待activity

(1)用sleep太浪費時間了,並且不知道什麼時候能啟動完成,所以儘量不用sleep,巨集哥也不推薦使用。因為這個確實是太low了。

(2)上一步已經獲取當主頁面的activity了,那就可以用wait_activity等它出現了,再做下一步的點選操作

(3)參考程式碼

 1 # coding=utf-8
 2 # 1.先設定編碼,utf-8可支援中英文,如上,一般放在第一行
 3 
 4 # 2.註釋:包括記錄建立時間,建立人,專案名稱。
 5 '''
 6 Created on 2019-7-26
 7 @author: 北京-巨集哥   QQ交流群:707699217
 8 Project:學習和使用appium自動化測試-元素等待
 9 '''
10 # 3.匯入模組
11 from appium import webdriver
12 from time import sleep
13 desired_caps = {
14                 'platformName': 'Android',
15                 'deviceName': '127.0.0.1:62001',
16                 'platformVersion': '4.4.2',
17                 'appPackage': 'com.baidu.yuedu',
18                 'appActivity': 'com.baidu.yuedu.splash.SplashActivity'
19                 }
20 driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
21 
22 # sleep(10)  # 不用sleep
23 
24 # 獲取當前介面activity
25 ac = driver.current_activity
26 print(ac)
27 
28 # 等主頁面activity出現,30秒內
29 driver.wait_activity(".base.ui.MainActivity", 30)
30 
31 # 點知道了
32 driver.find_element_by_id("com.baidu.yuedu:id/positive").click()

5.  好了,關於元素等待目前就說這麼多!!!

您的肯定就是我進步的動力。如果你感覺還不錯,就請鼓勵一下吧!記得點波 推薦 哦!!!(點選右邊的小球即可,膽子大的可以試一下 :))

個人公眾號

微信群