標籤:mdr 思維 wait 自動化測試 webdriver exception des ppp false
?9.1 等待函數的使用9.1.1 為什麼要使用等待函數
我們在做自動化的時候很多時候都不是很順利,不是因為app的問題,我們的指令碼也沒問題,但是很多時候都會報錯,比如一個頁面本來就有id為1的這個元素,可是我無論怎麼定位他都沒辦法操作,然後報錯,這個是怎麼個情況呢?因為當我們app開啟一個頁面的時候我們的appium的運行速度過快那麼可能害沒有將頁面的資源解析完成然後你就去操作了,這樣能行嗎?肯定不行的,這樣不報錯誰錯呢?所以在很多的時候我們都需要載入等待時間的。那我們是不是盲目的去每個頁面都載入等待時間呢?
9.1.2 什麼時候使用等待函數
答案肯定是否定的,自動化的目的是高效,但是你每個頁面都去添加等待時間那麼執行下來的效率是不是大大降低了?估計你的領導該找你談話了。在載入等待時間時我們需要根據自己的判斷去增加,比如一些頁面資源較多載入慢了那你肯定需要加的。是不是都是這樣呢?其實不是的,所以這個就有了下面我們需要講的知識點,幾種不同類型的等待。
9.2 強制等待9.2.1 什麼是強制等待
故名思義就是你必須給我等,有點耍流氓的意思。比如:我進入到登陸頁面,剛好有一個強制等待的函數,那麼結果就是無論頁面的資源載入完沒有你都得給我等著。懂了嗎?只要時間沒到你就給我等著!哈哈,就像那啥一樣蠻不講理哈。
9.2.2 強制等待使用
在python裡面這個比較好,他調用的是time包下的等待函數,代碼如下:
#coding = "utf-8"import timetime.sleep(10)
首先是需要匯入time的包,下面一句話就搞定,是不是方便、實用呢?你偵錯工具的時候這樣寫寫就好,千萬別在實際項目中多用。因為這個time的等待是線程的死等,就是無論如何都會執行這一條語句,如果你在實際項目中去運行那麼你會發現效率會很慢。所以實際項目不推薦。
備忘:時間是按秒計算
9.2.3 強制等待封裝實戰
前面我們學了函數的封裝,如果我們這個等待函數需要在很多地方用到是不是每個地方都要來這麼一句呢?其實不是的,程式最重要的目的就是我們能夠少寫哪怕是一個單詞我們都要進行封裝,這是我的理解。實現同樣的功能為什麼不挑簡單的方法做呢?對吧。看封裝代碼:
#conding="utf-8"import timefrom appium import webdriverimport os def Case(platformName,platformVersion,deviceName,app,appPackage,appActivity): PATH = lambda p: os.path.abspath(os.path.join(os.path.dirname(__file__), p)) #print getConfig("baseconf", "platformName") desired_caps = {} desired_caps[‘platformName‘] = platformName #設定平台 desired_caps[‘platformVersion‘] = platformVersion #系統版本 desired_caps[‘deviceName‘] = deviceName #裝置id desired_caps[‘autoLaunch‘] = ‘true‘ #是否自動啟動 desired_caps[‘noReset‘] = ‘true‘ desired_caps[‘newCommandTimeout‘] = 20 desired_caps[‘app‘] = PATH(app)#安裝包路徑,放在該py檔案的目錄下) desired_caps[‘appPackage‘] = appPackage #包名 desired_caps[‘appActivity‘] = appActivity #啟動的activity driver = webdriver.Remote(‘http://localhost:4723/wd/hub‘, desired_caps) waitFor(5) #等待函數def waitFor(t): time.sleep(t)
看見這個代碼大家是不是有種朦朧的感覺?其實這個就是上一章節讓大家下去思考的,我將我們啟動的參數做了一個簡單的封裝,然後將等待函數也進行了封裝,然後他倆結合就成了現在的樣子。是不是很簡單?其實我想告訴你的是這個在真的自動化中不算自動化,但是大家需要慢慢的養成這個思維,多練習。在上面的代碼中我們將我們啟動app的代碼進行了一個簡單的重構封裝,這個時候對於初學者來說強烈建議大家動手操作,不然你不知道你是否能夠啟動,而且上面各行代碼什麼意思一定要搞清楚。
9.3 隱式等待
隱式等待可能對於剛學的人來說比較模糊,不知道是什麼意思,大家可以這樣理解,智能等待。為什麼這麼說呢,我們需要先瞭解了他的用處那麼為什麼這麼叫也就很明白了,首先我們看下面的代碼:
driver.implicitly_wait(10)
上面代碼就是隱式等待,他的語句就是這樣很簡單。但是你有思考過一個問題沒,為什麼這個等待是使用的driver?這裡需要說的是因為這個等待函數是webdriver提供的一個等待函數。那麼問題又來了,既然是webdriver提供的等待函數為什麼沒看到他指定需要的等待對象呢?有沒有思考過這個問題呢?因為這裡的等待函數是針對我們整個driver的。也就是說你只要是用driver去操作一個對象,或者一個元素,當你找不到這個元素或者對象的時候他就會自動的去等待你設定的這個逾時時間,如果在逾時時間內還沒有找到,程式就會報錯。是不是感覺這個等待太高大上了?還不動手練習去。
可能又有人會提出疑問說:為什麼你這了又driver,我沒有啊,或者說我按照你強制等待那樣將啟動的封裝了,然後隱式等待我也這樣封裝了,然後我這個就報錯了,為什嗎?首先思考一下,你回去把我們產生driver的地方去掉封裝,然後運行這樣的一句話就不是就不會報錯,嘗試一下。但是封裝就報錯,為什嗎?因為我們這裡沒有把driver返回出去,也就是說我們需要用到的driver現在是沒有被定義的,那麼肯定會報錯,那我如何和前面的代碼一樣封裝呢?看下面:
#conding="utf-8"import timefrom appium import webdriverimport os def Case(platformName,platformVersion,deviceName,app,appPackage,appActivity): PATH = lambda p: os.path.abspath(os.path.join(os.path.dirname(__file__), p)) #print getConfig("baseconf", "platformName") desired_caps = {} desired_caps[‘platformName‘] = platformName #設定平台 desired_caps[‘platformVersion‘] = platformVersion #系統版本 desired_caps[‘deviceName‘] = deviceName #裝置id desired_caps[‘autoLaunch‘] = ‘true‘ #是否自動啟動 desired_caps[‘noReset‘] = ‘true‘ desired_caps[‘newCommandTimeout‘] = 20 desired_caps[‘app‘] = PATH(app)#安裝包路徑,放在該py檔案的目錄下) desired_caps[‘appPackage‘] = appPackage #包名 desired_caps[‘appActivity‘] = appActivity #啟動的activity driver = webdriver.Remote(‘http://localhost:4723/wd/hub‘, desired_caps) waitFor(5) return driver #等待函數def waitFor(t): time.sleep(t)#隱式等待def implicit_for_wait(t): driver = Case(platformName,platformVersion,deviceName,app,appPackage,appActivity) driver.implicitly_wait(t)
再回過頭去看代碼是不是發現了不一樣的地方?這裡我們將初始化的driver進行了一個閉包,也就是給出了一個傳回值,然後我們在隱式等待中將我們的driver進行調用,然後他就擁有了driver,所以這個時候就能夠像上面的代碼一樣進行調用該等待方法了。
9.4 顯式等待
前面我們講了隱式等待和強制等待,下面我們看看顯示等待,同樣的先看代碼:
WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None)
首先我們來弄明白這個方法裡面幾個參數的含義:
1、driver:是我們操作的driver。
2、timeout:逾時時間,也就是我們找這個元素要找多久
3、poll_frequency:間隔時間,怎麼理解?就是說在逾時時間內每多少秒去查詢一次,預設情況是0.5秒一次
4、ignored_exceptions:異常,就是沒有找到程式拋出什麼異常。在預設情況是跑出:NoSuchElementException
在一般情況下我們只需要填寫前面兩個就行。看到這裡是否發現一個問題,這個也沒有定位元素,只是driver和時間。是不是也是全域的呢?答案肯定是否定的。在一般的情況下顯式等待是需要和其他方法一起結合的,看下面完整的代碼:
driver = self.driverWebDriverWait(driver, 10,5).until(lambda driver:driver.find_element_by_id("ssss"))
這個代碼是不是又看不懂了?我們再接著按照剛才的方法把這個代碼重構一下:
#conding="utf-8"import timefrom appium import webdriverimport os def Case(platformName,platformVersion,deviceName,app,appPackage,appActivity): PATH = lambda p: os.path.abspath(os.path.join(os.path.dirname(__file__), p)) #print getConfig("baseconf", "platformName") desired_caps = {} desired_caps[‘platformName‘] = platformName #設定平台 desired_caps[‘platformVersion‘] = platformVersion #系統版本 desired_caps[‘deviceName‘] = deviceName #裝置id desired_caps[‘autoLaunch‘] = ‘true‘ #是否自動啟動 desired_caps[‘noReset‘] = ‘true‘ desired_caps[‘newCommandTimeout‘] = 20 desired_caps[‘app‘] = PATH(app)#安裝包路徑,放在該py檔案的目錄下) desired_caps[‘appPackage‘] = appPackage #包名 desired_caps[‘appActivity‘] = appActivity #啟動的activity driver = webdriver.Remote(‘http://localhost:4723/wd/hub‘, desired_caps) waitFor(5) return driver #等待函數def waitFor(t): time.sleep(t) #隱式等待def implicit_for_wait(t): driver = Case(platformName,platformVersion,deviceName,app,appPackage,appActivity) driver.implicitly_wait(t)#顯示等待def wait(t): driver = Case(platformName,platformVersion,deviceName,app,appPackage,appActivity) WebDriverWait(driver, 10,5).until(lambda driver:driver.find_element_by_id("ssss"))
這裡python基礎不好的讀者會有一定困難,前面的不講解。先看lambda後面的代碼,他是一個匿名函數,冒號前面的是參數,冒號後面的是傳回值,driver是我們需要傳入的一個參數,類似下面的代碼:
def appiumDriver(driver): return driver.find_element_by_id("xxxxx");
他們倆的意思是一樣的。接著看.until方法,他給出的解釋是:調用該方法提供的驅動程式作為一個參數,直到傳回值不為 False。那麼整指令碼的意識翻譯過來是不是在10秒內每5秒去尋找一個id為sss的元素,如果沒找到那麼就報錯。
在自動化中我們需要的是不斷去學習新的思想,程式永遠是跟著思想走的,如果說你的思想很好了,那麼指令碼怎麼實現就相對而言很簡單了。
Appium python自動化測試系列之等待函數如何進行實戰(九)