1. 程式人生 > >Appium python自動化測試系列之等待函數如何進行實戰(九)

Appium python自動化測試系列之等待函數如何進行實戰(九)

可能 res path 定位 __file__ poll 9.1 慢慢 定義

?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 time
time.sleep(10)

首先是需要導入time的包,下面一句話就搞定,是不是方便、實用呢?你調試程序的時候這樣寫寫就好,千萬別在實際項目中多用。因為這個time的等待是線程的死等,就是無論如何都會執行這一條語句,如果你在實際項目中去運行那麽你會發現效率會很慢。所以實際項目不推薦。

備註:時間是按秒計算

9.2.3 強制等待封裝實戰

前面我們學了函數的封裝,如果我們這個等待函數需要在很多地方用到是不是每個地方都要來這麽一句呢?其實不是的,程序最重要的目的就是我們能夠少寫哪怕是一個單詞我們都要進行封裝,這是我的理解。實現同樣的功能為什麽不挑簡單的方法做呢?對吧。看封裝代碼:

#conding="utf-8"
import time
from appium import webdriver
import 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 time
from appium import webdriver
import 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.driver
WebDriverWait(driver, 10,5).until(lambda driver:driver.find_element_by_id("ssss"))

這個代碼是不是又看不懂了?我們再接著按照剛才的方法把這個代碼重構一下:

#conding="utf-8"
import time
from appium import webdriver
import 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自動化測試系列之等待函數如何進行實戰(九)