WebDriver的get()方法只會在當前窗口( current browser window)加載頁面,並且會阻塞程序的運行,直至頁面加載完畢(onload)或者超時,超時可以通過在初始化實例時進行設置:
1 webDriver.manage().timeouts().pageLoadTimeout(10, TimeUnit.SECONDS);//設置為10秒的超時
如果需要用一個WebDriver實例同時操作多個浏覽器窗口,需要留意該特性造成的影響。默認一個WebDriver實例只會打開一個浏覽器窗口,但可以使用中轉頁面或通過javascript:偽協議,popup出多個浏覽器窗口。
對於並發測試需求,由於get的阻塞和javascript單線程執行特性,應該采用多線程來實現。
於get()方式類似的還有WebDriver.Navigation接口的to()方法,WebDriver.Navigation還有back()、forward()、refresh()方法來實現浏覽器的歷史導航(back()、forward()實現的是單步歷史導航,不接收步長參數)
Selenium WebDriver也可以通過Selenium Standalone Server實現跨服務器的浏覽器調用,具體實現參考官方文檔。
WebDriver.Timeouts接口還有另外兩個方法,setScriptTimeout()和implicitlyWait():
使用setScriptTimeout()方式可以設置等待一個異步腳本在拋出錯誤之前執行的時長。
使用implicitlyWait()方式可以設置查找元素時在拋出NoSuchElementException錯誤之前的等待時長,這是一個隱性的或稱為全局的設置。與之對應的是Explicit Waits,具體可參考http://docs.seleniumhq.org/docs/04_webdriver_advanced.jsp#explicit-and-implicit-waits。
Timeout值的設置需要根據實際需求合理設置並調優,設置了過短,在程序運行過程中將會拋出大量超時錯誤,過長又會降低程序效率。
另外Timeout不恰當的設置,將會在程序運行過程中,產生不可預期的等待效果,比如同時設置了顯性和隱性超時時長,那麼查找元素的超時時長將不確定。
當頁面中含有frame,如果需要查找frame內部的元素,需要先使用webDriver.switchTo().frame();切換到iframe內部,再進行查找操作。
1 webDriver.switchTo().frame(0);//switch to a frame by index
frame()有三個重載形式,可傳入frame的索引編號、frameElement、和name/handle字符串。如果需要切出,可以使用
1 webDriver.switchTo().defaultContent();
或
1 webDriver.switchTo().parentFrame();
兩者的區別在於defaultContent()會切換到第一個frame或者是頂層頁面;parentFrame()會切換到父一級的frame。
那麼遍歷iframe包括嵌套的iframe,可通過遞歸實現,如:
1 public static void getFrame(){ 2 //do something 3 iLen = webDriver.findElements(By.cssSelector("body iframe")).size(); 4 for (i=0;i<iLen;i++) { 5 webDriver.switchTo().frame(i); 6 getFrame(); 7 webDriver.switchTo().parentFrame(); 8 }; 9 }
iframe可以嵌入自己所在的頁面嗎?答案是可以的,但不會無限制嵌入下去,只會嵌入3層,之後在內部第三層的frame就不會再嵌入了。
有些網站會用自動跳轉的方法處理404錯誤,當有頁面通過frame被嵌入到跳轉目標頁,如果該頁面不存在,就產生了頁面嵌套自身的情況,在使用Selenium WebDriver對這類iframe內容查找時,如果遍歷frame的策略不當,會產生frame遍歷的死循環或者導致程序拋出NoSuchFrameException異常。
2.21版本chromedriver,使用webDriver.getCurrentUrl()獲取頁面的url時,跟舊版本不同,在switchTo()到一個frame後,不會返回該frame的url,永遠只會返回頂層頁面的url。通過獲取frame的src屬性來識別frame頁面也不是100%可靠,因為frame的頁面內容是可以動態寫入的。
如果需要在遍歷frame的時候控制遞歸遍歷深度,可以設置一個深度閥值,在遞歸過程中當達到該閥值時返回,如:
1 static int fDepth = 2; 2 public static void getFrame() { 3 //do something 4 if (fDepth>0) { 5 iLen = webDriver.findElements(By.cssSelector("body iframe")).size(); 6 for (int i=0;i<iLen;i++) { 7 fDepth--; 8 webDriver.switchTo().frame(i); 9 getFrame(); 10 fDepth++; 11 webDriver.switchTo().parentFrame(); 12 }; 13 }; 14 };
Selenium WebDriver在實際使用過程中,執行速度很慢,怎麼辦?
待續!
原創文章,轉載請標明出處。