你需要知道的有關(guān)Selenium異常處理的都在這兒
譯文【51CTO.com快譯】在Java技術(shù)領(lǐng)域,異常處理是一直伴隨著編程本身,被頻繁提及的“古老”話題。在程序代碼執(zhí)行的過(guò)程中,倘若我們無(wú)法對(duì)產(chǎn)生的異常情況,采用及時(shí)、妥善的處理,那么很可能會(huì)導(dǎo)致應(yīng)用服務(wù)產(chǎn)生異常行為或中斷。當(dāng)然,代碼異常并不可怕,它非但是現(xiàn)代化編程的基本組成部分,而且有助于開(kāi)發(fā)者知曉該在何時(shí)、以及如何處理哪些錯(cuò)誤。下面,我們將和您討論如何“優(yōu)雅地”處理異常,甚至利用異常處理,來(lái)編寫(xiě)出更加整潔、更易于維護(hù)的程序代碼。
什么是異常?
顧名思義,作為程序員的一種常用術(shù)語(yǔ),“異常”與任何特定的編程語(yǔ)言無(wú)關(guān)。它屬于程序因?yàn)橥蝗恢兄?,而未能交付出預(yù)期輸出的事件。通常,引發(fā)異常出現(xiàn)的潛在因素往往來(lái)自如下方面:
- Java虛擬內(nèi)存(JVM)的不足
- 請(qǐng)求訪問(wèn)的文件在目標(biāo)系統(tǒng)中不存在
- 用戶提供了無(wú)效的數(shù)據(jù)
- 在正常的通信過(guò)程中突然出現(xiàn)斷網(wǎng)
Java中的異常類型
1. 已查明的異常(Checked Exceptions):編譯器在編譯的過(guò)程中,會(huì)檢查到這些異常,并驗(yàn)證它們是否已被處理。如果未被處理,系統(tǒng)會(huì)報(bào)告編譯錯(cuò)誤。因此它們被通稱為編譯時(shí)異常(compile-time exceptions)。下面是一些常見(jiàn)的此類異常示例:
- SQLException:程序在基于SQL語(yǔ)法執(zhí)行數(shù)據(jù)庫(kù)查詢時(shí),可能會(huì)產(chǎn)生此類異常。
- IOException:程序在文件上執(zhí)行無(wú)效的I/O流操作時(shí),可能會(huì)產(chǎn)生此類異常。
- ClassNotFoundException:當(dāng)JVM無(wú)法找到所需的Java類時(shí),可能會(huì)產(chǎn)生此類異常。
2. 未查明的異常(Unchecked Exceptions):這些異常是在程序的執(zhí)行期間發(fā)生的邏輯錯(cuò)誤,因此通常稱為運(yùn)行時(shí)異常(Runtime Exceptions)。此類異常在編譯時(shí)未被檢查出來(lái),或者在整個(gè)編譯過(guò)程中已被忽略。下面是一些典型的此類異常示例:
- NullPointerException:當(dāng)訪問(wèn)具有空值的對(duì)象時(shí),可能會(huì)產(chǎn)生此類異常。
- ArrayIndexOutofBound:當(dāng)使用無(wú)效的索引值去訪問(wèn)數(shù)組時(shí),可能會(huì)產(chǎn)生此類異常。
- IllegalArgumentException:當(dāng)程序?qū)⒉徽_的參數(shù)傳遞給方法時(shí),可能會(huì)產(chǎn)生此類異常。
- NumberFormatException:當(dāng)程序?qū)⒆址畟鬟f給無(wú)法轉(zhuǎn)換為數(shù)字的方法時(shí),可能會(huì)產(chǎn)生此類異常。
- ArithmeticException:當(dāng)程序執(zhí)行不正確的算術(shù)運(yùn)算(例如將數(shù)字除以零)時(shí),可能會(huì)產(chǎn)生此類異常。
異常處理標(biāo)準(zhǔn)
通過(guò)對(duì)異常處理能力的提升,我們不僅可以保持代碼的整潔,而且能夠增強(qiáng)其可維護(hù)性、可擴(kuò)展性和可閱讀性。當(dāng)然,不同的面向?qū)ο缶幊?Object-Oriented Programming,OOP)語(yǔ)言,具有不同的異常處理方法。以下是一些常用的Java異常處理標(biāo)準(zhǔn):
Try-Catch:該關(guān)鍵字組合可被用于捕獲異常。其中,try塊應(yīng)當(dāng)被放在開(kāi)頭,而catch塊應(yīng)被放在try塊的末尾,以便捕獲異常,并采取必要的行動(dòng)。也就是說(shuō),我們可以在遇到異常時(shí),創(chuàng)建異常類的對(duì)象,以便使用以下預(yù)定義的方法,來(lái)顯示調(diào)試信息:
- printStackTrace():該函數(shù)可用于打印棧的跟蹤、異常的名稱、以及其他重要的異常信息。
- getMessage():此函數(shù)有助于獲取針對(duì)異常的深入描述。
- try
- {
- // Code
- } catch(Exception e){
- // Code for Handling exception
- }
同時(shí),Try-Catch塊也可以用其他高級(jí)方法來(lái)處理異常,例如,我們可能希望從單個(gè)代碼塊中捕獲多個(gè)異常,那么就可以通過(guò)在try塊之后的多個(gè)catch塊,去處理不同的異常。而且,我們?cè)趖ry塊之后,使用無(wú)限數(shù)量的catch塊。
- try
- {
- //Code
- } catch(ExceptionType1 e1){
- //Code for Handling Exception 1
- } catch(ExceptionType2 e2){
- //Code for Handling Exception 2
- }
Throw/Throws:如果程序員想顯式地拋出異常,那么可以使用throw關(guān)鍵字,與要在運(yùn)行時(shí)處理的異常對(duì)象協(xié)同使用。
- public static void exceptionProgram()throws Exception{
- try {
- // write your code here
- } Catch(Exception b){
- // Throw an Exception explicitly
- throw(b); }
- }
如果開(kāi)發(fā)者想拋出多個(gè)異常,則可以通過(guò)在方法簽名的子句中使用throws關(guān)鍵字來(lái)拋出,并且由方法的調(diào)用者去進(jìn)行異常處理。
- public static void exceptionProgram()throws ExceptionType1, ExceptionType2{
- try {
- // write your code here
- } catch(ExceptionType1 e1){
- // Code to handle exception 1
- } catch(ExceptionType1 e2){
- // Code to handle exception 2
- }
finally:該個(gè)代碼塊往往是在try-catch塊之后被創(chuàng)建的。也就是說(shuō),無(wú)論是否拋出異常,它都會(huì)被執(zhí)行。
- try {
- //Code
- } catch(ExceptionType1 e1){
- //Catch block
- } catch(ExceptionType2 e2){
- //Catch block
- } finally {
- //The finally block always executes.
- }
Selenium中的常見(jiàn)異常
WebDriverException定義了Selenium中的多種異常,我們從中選取最常見(jiàn)的異常予以介紹,并配上簡(jiǎn)單的針對(duì)Selenium的異常處理方案:
1. NoSuchElementException
當(dāng)WebDriver無(wú)法定位所需要元素時(shí),Selenium可能會(huì)產(chǎn)生此類異常。此處的NoSuchElementException是NotFoundException類的子類,它通常出現(xiàn)在程序使用了無(wú)效的定位器時(shí)。
此外,如果WebDriver仍然停留在上一頁(yè)、或正在加載下一頁(yè),而所需的定位器已到達(dá)了下一頁(yè)時(shí),就會(huì)因?yàn)樵撗舆t而出現(xiàn)異常。為此,我們應(yīng)當(dāng)通過(guò)適當(dāng)?shù)牡却幚頊y(cè)試,最大限度地減少此類異常的發(fā)生。
當(dāng)然,此類異??梢栽赾atch塊中被捕獲到,并且可以在其中執(zhí)行所需的操作,以繼續(xù)完成自動(dòng)化的測(cè)試。例如:
- try { driver.findElement(By.id("form-save")).click(); } catch(NoSuchElementException e){
- System.out.println(“WebDriver couldn’t locate the element”); }
2. NoSuchWindowException
該異常也是NotFoundException類的子類。如果WebDriver嘗試著切換到無(wú)效的瀏覽器窗口,那么WebDriver將拋出NoSuchWindowException。因此,要實(shí)現(xiàn)窗口切換的好方法是,首先獲取活動(dòng)窗口的會(huì)話,然后在對(duì)應(yīng)的窗口上執(zhí)行所需的操作。例如:
- for(String windowHandle : driver.getWindowHandles()){
- try { driver.switchTo().window(handle); } catch(NoSuchWindowException e){ System.out.println(“Exception while switching browser window”); }
- }
3. NoAlertPresentException
當(dāng)WebDriver嘗試著切換到某個(gè)不存在或無(wú)效的警報(bào)時(shí),Selenium可能會(huì)產(chǎn)生此類異常。對(duì)此,我建議開(kāi)發(fā)者使用顯式、或適當(dāng)?shù)牡却龝r(shí)間,來(lái)處理瀏覽器的各類警報(bào)。倘若仍然等不到警報(bào)的話,catch塊可以捕獲該異常。例如:
- try {
- driver.switchTo().alert().accept(); } catch(NoSuchAlertException e){
- System.out.println(“WebDriver couldn’t locate the Alert”); }
4. ElementNotVisibleException
該異常被定義為ElementNotInteractableException類的子類。當(dāng)WebDriver嘗試著對(duì)不可見(jiàn)的元素、或不可交互的元素執(zhí)行各項(xiàng)操作時(shí),Selenium可能會(huì)產(chǎn)生此類異常。對(duì)此,我建議開(kāi)發(fā)者在的確需要之處,讓Selenium進(jìn)行適當(dāng)?shù)某瑫r(shí)等待。例如:
- try { driver.findElement(By.id("form-save")).click(); } catch(ElementNotVisibleException e){
- System.out.println(“WebDriver couldn’t locate the element”); }
5. ElementNotSelectableException
該異常屬于InvalidElementStateException類的子類。在Selenium中,ElementNotSelectableException表明某個(gè)元素雖然存在于網(wǎng)頁(yè)上,但是無(wú)法被WebDriver所選擇。
catch塊不但可以處理Selenium中的此類異常,而且可以使用相同或不同的技術(shù),重新選擇相同的元素。例如:
- try {
- Select dropdown = new Select(driver.findElement(By.id(“swift”))); } catch(ElementNotSelectableException e){
- System.out.println("Element could not be selected")}
6. NoSuchSessionException
Selenium通過(guò)driver.quit()命令退出自動(dòng)化的瀏覽器會(huì)話后,以及在調(diào)用某個(gè)測(cè)試方法時(shí),會(huì)產(chǎn)生此類異常。當(dāng)然,如果瀏覽器崩潰或出現(xiàn)斷網(wǎng),該異常也可能會(huì)發(fā)生。為了避免出現(xiàn)NoSuchSessionException,我們可以在測(cè)試套件結(jié)束時(shí),退出瀏覽器,并確保用于自動(dòng)化測(cè)試的瀏覽器版本的穩(wěn)定性。例如:
- private WebDriver driver;
- @BeforeSuite
- public void setUp(){ driver = new ChromeDriver(); }
- @AfterSuite
- public void tearDown(){ driver.quit(); }
7. StaleElementReferenceException
當(dāng)DOM中不再存在程序所需的元素時(shí),Selenium將拋出StaleElementReferenceException。當(dāng)然,如果DOM未能被正確加載、或WebDriver被卡在錯(cuò)誤的頁(yè)面上時(shí),也可能會(huì)產(chǎn)生這種異常。對(duì)此,您可以使用catch塊捕獲該異常,并且使用動(dòng)態(tài)的XPath、或嘗試著重新刷新頁(yè)面。例如:
- try { driver.findElement(By.xpath(“//*[contains(@id,firstname’)]”)).sendKeys(“Aaron”);
- } catch(StaleElementReferenceException e){
- System.out.println("Could not interact with a desired element")}
8. TimeoutException
當(dāng)WebDriver超過(guò)了執(zhí)行下一步的等待時(shí)限時(shí),Selenium中可能會(huì)產(chǎn)生此類異常。Selenium的各種等待通常被用于避免出現(xiàn)ElementNotVisibleException之類的異常。不過(guò),即使在使用了適當(dāng)?shù)牡却?,如果元素仍然不可交互,那么TimeoutException也會(huì)被拋出。為此,我們必須通過(guò)執(zhí)行手動(dòng)測(cè)試,來(lái)檢驗(yàn)元素的延時(shí)性,以便采取進(jìn)一步的處理等待。
9. InvalidSelectorException
當(dāng)使用無(wú)效的或不正確的選擇器時(shí),Selenium中會(huì)拋出此類異常。當(dāng)然,類似情況也可能發(fā)生在創(chuàng)建XPATH時(shí)。對(duì)此,我們需要在將代碼推送到主分支之前,檢查測(cè)試腳本,并測(cè)試腳本的端到端流程。此外,SelectorHub和ChroPath等工具,也可以被用于驗(yàn)證定位器。
10. NoSuchFrameException
NoSuchFrameException屬于NotFoundException類的子類。當(dāng)WebDriver嘗試著切換到當(dāng)前網(wǎng)頁(yè)上無(wú)效的、或不存在的框架時(shí),Selenium可能會(huì)產(chǎn)生此類異常。為此,我們需要首先確保框架的名稱或id是正確的;其次,應(yīng)確??蚣艿募虞d不會(huì)過(guò)于消耗時(shí)間。當(dāng)然,如果在網(wǎng)頁(yè)上加載框架的確非常耗時(shí)的話,則需要修正相應(yīng)的等待處理。例如:
- try {
- driver.switchTo().frame("frame_1"); } catch(NoSuchFrameException e){
- System.out.println("Could not find the desired frame")
- }
小結(jié)
綜上所述,為了適應(yīng)各種場(chǎng)景,異常處理對(duì)于任何自動(dòng)化腳本和邏輯結(jié)構(gòu)都是至關(guān)重要的。請(qǐng)您務(wù)必在了解每個(gè)異常特征的基礎(chǔ)上,有選擇性地在自動(dòng)化腳本中使用上述十種有關(guān)Selenium的常用異常處理命令。
原文標(biāo)題:All You Need To Know About Exception Handling In Selenium,作者:Ramit Dhamija
【51CTO譯稿,合作站點(diǎn)轉(zhuǎn)載請(qǐng)注明原文譯者和出處為51CTO.com】