1.簡介
前邊講解完八大元素定位大法,今天宏哥講解和分享一下三大延時等待。宏哥這里簡稱“三等八定”。很多人在群里問,這個下拉框定位不到、那個彈出框定位不到…各種定位不到,其實大多數情況下就是兩種問題:1. 有frame,2. 沒有加等待。殊不知,你的代碼運行速度是什么量級的,而瀏覽器加載渲染速度又是什么量級的,就好比閃電俠和凹凸曼約好去打怪獸,然后閃電俠打完回來之后問凹凸曼你為啥還在穿鞋沒出門?凹凸曼分分中內心一萬只羊駝飛過,欺負哥速度慢,哥不跟你玩了,拋個異常撂挑子了。
那么怎么才能照顧到凹凸曼緩慢的加載速度呢?只有一個辦法,那就是等嘍。說到等,又有三種等法,且聽宏哥一一道來。
2.為啥要等待?
有時候我們做自動化測試,需要等待。因為我們的下一步執行依賴於上一步的執行結果,因為程序執行的是很快的,上一步執行完畢馬上執行下一步,有時候上一步的結果還沒加載出來,下一步就執行了,這樣就會造成錯誤,比如No suchElement Exception有時候就是因為這樣造成的。
我們經常會碰到用selenium操作頁面上某個元素的時候,需要等待頁面加載完成后, 才能操作。 否則頁面上的元素不存在,會拋出異常。
或者碰到AJAX異步加載,我們需要等待元素加載完成后,才能操作。在進行UI自動化測試時,需要等元素加載完成,才能對元素進行操作,不然找不到元素會報錯,因此需要增加等待在上篇selenium+java元素定位的使用中。
3.Selenium的三大等待
3.1硬性等待(sleep)
先講強制等待,大家應該都不會陌生,sleep就是強制等待。硬性等待也稱為強制等待、線程休眠。強制等待,顧名思義就是強迫你等待唄,你等也得等不等也得等,沒有商量。不管頁面是否加載完,強制指定等待時間后繼續執行。不建議用這種方式。此種等待方法直接調用Thread.sleep()方法來進行線程等待,由於此方法較為死板,不夠靈活,會導致腳本運行時間變長,故建議盡量少用
Thread.sleep():固定休眠時間設置,Java的Thread類里提供了休眠方法sleep,導入包后就能使用
sleep()方法以毫秒為單位
只要在case中加入sleep就會強制等待設置的時間后才會執行之后的命令,這種等待一般適用於調試腳本的時候。
java代碼,采用方式如下:
Thread.sleep(3000);----------表示線程等待3秒,執行到此時不管什么就固定的等待三秒之后再接着執行后面的操作。
封裝方法如下:
public static void wait(int second){ try { Thread.sleep(second*3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
優缺點:硬性等待使用簡單,但由於不知道一個線程需要等待多久,時間設置小了不行,設置長了往往會造成時間的浪費,影響性能。
3.2隱式等待(ImplicitlyWait)
implicitlyWait()方法比sleep()方法智能,sleep()方法只能在一個固定的時間等待,而implicitlyWait()可以在一個時間范圍內等待,稱為隱式等待。
隱式等待,是設置的全局等待。設置等待時間,是對頁面中的所有元素設置加載時間,如果元素不是馬上就能定位成功就會在固定等待時長內不停去搜索元素,在設置時間內發現元素則執行后面操作,如果超出了設置的時間還沒發現元素則拋出異常。隱式等待可以理解成在規定的時間范圍內,瀏覽器在不停的刷新頁面,直到找到相關元素或者時間結束。
隱式等待采用全部設置,也就是說,你所有的findElement方法都會隱式等待10s,java代碼,采用方式如下:
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
----此方法針對執行腳本的所有對象,等待10秒
timeouts()---->驅動超時對象,該對象可以進行多種場景的等待超時設置,而implicitlyWait即為隱式等待,會在設置的時間內不停查找元素或超時
隱式等待一般是在driver初始化之后設置,只用設置一次,全局生效可用,只適用於找元素findElement方法,其它方法沒有等待效果,找到元素后就停止了,如果找到元素的時間大於設置的時間,則報一個找不到元素的異常。
此處共有三個方法,分別為查找元素的等待超時時間、頁面加載等待超時時間和js腳本運行超時時間,方法如下代碼所示:
System.setProperty("webdriver.chrome.driver", "D:\\test\\driver\\chromedriver.exe"); ChromeDriver chrome = new ChromeDriver(); //此處為設定頁面加載超時時間為30s chrome.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS); //此處為設定元素查找最長超時時間為10s chrome.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); //此處為設置js腳本運行超時時間為30s chrome.manage().timeouts().setScriptTimeout(30, TimeUnit.SECONDS);
優缺點:隱式等待相對靈活,但是設置是針對全局的,並不是所有的元素都需要等待,也不能適用條件更復雜的情況,如元素肉眼不可點擊,元素不可見時不能用
3.3顯式等待(Explicit wait)
顯示等待是等待指定元素設置的等待時間,在設置時間內,默認每隔0.5s檢測一次當前的頁面這個元素是否存在,如果在規定的時間內找到了元素則執行相關操作,如果超過設置時間檢測不到則拋出異常。默認拋出異常為:NoSuchElementException。做自動化的時候推薦使用顯示等待。
顯式等待的意思,就是判斷這個元素是否加載完成,如果在規定的時間加載完成就進行下一步操作,如果在規定的時間沒有加載完成就拋出異常。顯式等待通常是自定義的一段代碼,用來等待某個條件發生后再繼續執行后續代碼。此種方式用於特定元素、特定條件的等待,使用靈活,建議使用這種方法來進行等待設置。
【場景1:登錄一個網站,輸入用戶名和密碼后,點擊登錄,需要加載好幾秒鍾才能進入用戶中心。例如你登錄你網銀,用戶名和密碼驗證通過后,它需要等幾秒,才能顯示你賬戶信息,這幾秒,它需要去數據庫查詢數據並顯示在前端。
場景2:你登錄一個旅行網站,填好了出發起點和目的地,點擊搜索,需要查詢等待幾秒,然后給你顯示車票信息。】
例子1:自帶的條件
顯式等待每隔一段時間掃描一次頁面,檢查元素是否滿足結果條件,檢查元素是否存在,不存在則繼續等待,直到找到或超時, 該方式不是全局設置 ,推薦使用
當頁面的某些元素需要鼠標放上去才展示出來時,顯示等待的presenceoOfElementLocatde方法相當隱式等待,不可直接點擊,需要配合鼠標操作才可點擊
例2:自定義條件
自定義條件需要自定義我們需要等待的條件
4.實戰
前邊文章中都用到過強制和隱式等待了,沒有用到過顯示等待,那么宏哥就在這里給小伙伴后者童鞋們來演示一下,以便更好的區分和理解。
實例:打開百度首頁面“更多”下拉頁面里的音樂頁面。
4.1測試用例
1.具體測試用例:
(1)打開百度首頁
(2)鼠標移動到首頁的“更多”
(3)等待出現“查看百度全部產品”
(4)定位音樂圖標並點擊
(5)獲取新打開頁面的title,進行斷言
4.2代碼設計
根據測試用例進行代碼設計如下圖所示:
4.3參考代碼
參考代碼如下:
package lessons; import junit.framework.Assert; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.interactions.Actions; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; /** * @author 北京-宏哥 * * 《手把手教你》系列技巧篇(二十一)-java+ selenium自動化測試-三大延時等待(詳細教程) * * 2021年8月18日 */ public class TestMusic { @SuppressWarnings("deprecation") public static void main(String [] args) throws InterruptedException { System.setProperty("webdriver.gecko.driver", ".\\Tools\\chromedriver.exe"); //指定驅動路徑 WebDriver driver = new ChromeDriver (); //最大化窗口 //driver.manage().window().maximize(); //打開百度首頁 driver.get("http://wwww.baidu.com"); //聲明一個Action對象 Actions action=new Actions(driver); //鼠標移動到 更多產品 上 action.moveToElement(driver.findElement(By.xpath("//a[text()='更多']"))).perform(); //顯示等待時間10s 等 全部產品>> 出現 WebDriverWait w=new WebDriverWait(driver,10); w.until(ExpectedConditions.presenceOfAllElementsLocatedBy(By.xpath("//a[text()='查看全部百度產品 >']"))); //等待的元素出現后點擊 音樂 WebElement cp=driver.findElement(By.xpath("//a/div[text()='音樂']")); cp.click(); //斷言音樂頁面的Title值為 千千音樂-聽見世界 Assert.assertEquals("千千音樂-聽見世界",driver.getTitle()); System.out.println("斷言通過!"); } }
4.4運行代碼
1.運行代碼,右鍵Run AS->java Application,控制台輸出,如下圖所示:
2.運行代碼后電腦端的瀏覽器的動作,如下小視頻所示:
3.瀏覽器實現結果,宏哥怕大家不注意視頻后瀏覽器實現結果,因此專門截圖,如下圖所示:
通過瀏覽器的實現結果,和代碼的運行結果,可以判斷出:即使web頁面已跳轉至新窗口,但是代碼邏輯還在原有窗口
為解決該問題,我們需要引入 句柄 的概念:窗口句柄 ,粗略的理解,每個窗口對應一個句柄,句柄可認為是一個唯一長字符串
有了前邊宏哥上下兩卷的窗口切換的介紹,想必你知道這是怎么回事了吧,那么解決此問題的方法就是不是相當簡單了,只需要切換一下窗口,進行斷言即可!
4.5優化后的參考代碼
package lessons; import junit.framework.Assert; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.interactions.Actions; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; /** * @author 北京-宏哥 * * 《手把手教你》系列技巧篇(二十四)-java+ selenium自動化測試-三大延時等待(詳細教程) * * 2021年8月28日 */ public class TestMusic { public static void main(String [] args) throws InterruptedException { System.setProperty("webdriver.gecko.driver", ".\\Tools\\chromedriver.exe"); //指定驅動路徑 WebDriver driver = new ChromeDriver (); //最大化窗口 driver.manage().window().maximize(); //打開百度首頁 driver.get("http://wwww.baidu.com"); //聲明一個Action對象 Actions action=new Actions(driver); //鼠標移動到 更多產品 上 action.moveToElement(driver.findElement(By.xpath("//a[text()='更多']"))).perform(); //顯示等待時間10s 等 全部產品>> 出現 WebDriverWait w=new WebDriverWait(driver,10); w.until(ExpectedConditions.presenceOfAllElementsLocatedBy(By.xpath("//a[text()='查看全部百度產品 >']"))); //等待的元素出現后點擊 音樂 WebElement cp=driver.findElement(By.xpath("//a/div[text()='音樂']")); cp.click(); //切換至新窗口 //首先,我們要先獲取到一個主句柄,作為燈塔,防止"迷路" String mainWindow = driver.getWindowHandle(); //接着我們要獲取所有的句柄信息,並賦值給 handles //String[] handles=new String[driver.getWindowHandles().size()]; //String handles = driver.getWindowHandles(); System.out.println("切換前的title:"+driver.getTitle()); //使用for循環,遍歷所有的handles,以便判斷 for (String temphandle:driver.getWindowHandles()){ if(!temphandle.equals(mainWindow)) driver.close(); driver.switchTo().window(temphandle); } //讓我們打印一下當前窗口的 title System.out.println("切換后的title:"+driver.getTitle()); //斷言音樂頁面的Title值為 千千音樂-聽見世界 Assert.assertEquals("千千音樂-聽見世界",driver.getTitle()); System.out.println("斷言通過!"); } }
4.6優化后代碼運行
1.運行代碼,右鍵Run AS->java Application,控制台輸出,如下圖所示:
2.運行代碼后電腦端的瀏覽器的動作,如下小視頻所示:
5.小結
1.三種等待方式比較起來,顯示等待花費的時間最短,也最靈活,所以在自動化測試中可以提高效率。比較推薦使用顯示等待。
2.隱形等待是設置了一個最長等待時間,如果在規定時間內網頁加載完成,則執行下一步,否則一直等到時間截止,然后執行下一步。注意這里有一個弊端,那就是程序會一直等待整個頁面加載完成,也就是一般情況下你看到瀏覽器標簽欄那個小圈不再轉,才會執行下一步,但有時候頁面想要的元素早就在加載完成了,但是因為個別js之類的東西特別慢,我仍得等到頁面全部完成才能執行下一步,我想等我要的元素出來之后就下一步怎么辦?有辦法,這就要看selenium提供的另一種等待方式——顯性等待wait了。
需要特別說明的是:隱性等待對整個driver的周期都起作用,所以只要設置一次即可,我曾看到有人把隱性等待當成了sleep在用,走哪兒都來一下…其實來一下,和你走哪兒都來一下的效果是一樣的。
3.不要混合隱式和顯式等待。這樣做可能會導致不可預測的等待時間。例如,設置 10 秒的隱式等待和 15 秒的顯式等待可能會導致在 20 秒后發生超時。
6.拓展
實戰中可能會遇到的問題:
代碼中:the import org.junit.Assert.* cannot be revolved
具體解決方法:
右鍵單擊項目名,選擇buildpath->add library,彈出配置對話框
選擇junit,next下一步