2015-12-13 42 views
0

我想開發一個AspectJ方面,它會自動吞下任何ElementNotVisibleExceptionStaleElementReferenceException S按硒-Java的WebDriver情況下拋出(的RuntimeException子類)(包括WebDriver多個子類 - ChromeDriverFirefoxDriver等)如何使用第三方maven dependency的執行切入點?

基本上,在非AOP上下文中處理ENVESERE異常的標準建議解決方案與Selenium是簡單地再試一次。然後再次。如果有必要,再一次。

像這樣的東西會在功能模式工作:使用webdriver的時後

public void tryWhileStale(Runnable r) 
{ 
     int n = 0; 
     while(n < 5) 
     { 
      try 
      { 
       r.run(); 
       break; 
      } 
      catch(StaleElementReferenceException | ElementNotVisibleException e){} 
      n++; 
      Thread.sleep(2000); 
     } 
     throw new RuntimeException("Timed out retrying"); 
} 

然後:

tryWhileStale(() -> driver.findElement(By.xpath(...)).click());

然而,這增加了不少額外的輸入(以及作爲意外忘記tryWhileStale()包裝的真實可能性)我想避免。

我不想下載selenium-java的副本,編輯源代碼並重新編譯,因爲我直接從公共Maven存儲庫中提取Selenium。

我希望AspectJ能夠弄清楚如何做到這一點,所以我做了一些研究,並意識到我需要around建議execution切入點。如果我使用call而不是execution,它將成功觸發,但它不會吞下異常。這對我來說是神祕的,因爲從我的代碼流中看來,我寫的方面會捕獲proceed()調用中引發的任何內容。

但是execution()切入點也不起作用!這是因爲AspectJ正在編織我的類,但是不編織Selenium-Java,即使我的pom.xml中有weaveDependency!該踢球是call()只適用於你的類是編織,而execution()只適用於如果你是是編織類。顯然,如果你有你的課程和第三方課程編織,任何一個都可以工作。

有沒有辦法做到這一點,而不會完全放棄AOP或Maven?下面是我的代碼應該據稱工作如果我能織硒的Java:

@Aspect 
class MyAspect { 

    @Around("execution (WebElement *.findElement(By))") 
    public Object around(ProceedingJoinPoint pjp) 
    { 
     Object f = null; 
     int n = 0; 
     do 
     { 
      try 
      { 
       System.err.println("Before " + this.toString()); 
       f = pjp.proceed(); 
       System.err.println("After " + this.toString()); 
       return f; 
      } 
      catch(Throwable t) 
      { 
       try { Thread.sleep(5000); } catch(InterruptedException ie) { break; } 
       System.err.println("Waiting 5 seconds because of " + t.getClass().getSimpleName()); 
      } 
      n++; 
     } while(n < 5); 
     System.err.println("Gave up waiting"); 
     return null; 
    } 
} 
+0

所以我想你應用這種方法來編織依賴http://www.mojohaus.org/aspectj-maven-plugin/examples/weaveJars.html,插件執行綁定到哪個階段? –

+0

在這種情況下,我看不到任何爲什麼'call()'不起作用的原因。你能否描述究竟是什麼問題? – kriegaex

回答

1

我有點好奇,並設置了一個方面截獲call(WebElement WebDriver+.findElement(*))(類似於你的方法)的示例項目和也call(void WebElement+.click())。我使用了sample page with an inline frame (iframe) from W3schools來模擬一些WebDriver例外,例如NoSuchElementExceptionStaleElementReferenceException。如果您只是將焦點從主框架切換到iframe並嘗試訪問前一個元素(反之亦然),這很容易。

我的示例方面不會等待n秒,而是遍歷主要和所有iframe,以便在該上下文中重新發出原始調用。根據需要調整示例代碼應該非常容易。

哦順便說一句,我使用本機AspectJ語法,而不是基於註釋的語法。我希望你不介意,我發現本地語法更具表現力和優雅。

的Maven POM建項目:

的pom.xml包含

  • 一些額外的插件建立一個單一的,executeable JAR(一個罐子)含AspectJ運行時和所有其他依賴項。分發和運行編譯的程序非常方便。
  • 我還包含exec-maven以便您可以通過mvn clean compile exec:java輕鬆運行您的程序。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 
    <modelVersion>4.0.0</modelVersion> 

    <groupId>de.scrum-master.stackoverflow</groupId> 
    <artifactId>selenium-aspectj-retry</artifactId> 
    <version>1.0-SNAPSHOT</version> 

    <name>Selenium auto-retry via AspectJ</name> 

    <properties> 
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
     <java.source-target.version>1.8</java.source-target.version> 
     <aspectj.version>1.8.7</aspectj.version> 
     <main-class>de.scrum_master.app.Application</main-class> 
    </properties> 

    <build> 
     <pluginManagement> 
      <plugins> 
       <plugin> 
        <groupId>org.apache.maven.plugins</groupId> 
        <artifactId>maven-compiler-plugin</artifactId> 
        <version>3.3</version> 
        <configuration> 
         <source>${java.source-target.version}</source> 
         <target>${java.source-target.version}</target> 
         <!-- IMPORTANT --> 
         <useIncrementalCompilation>false</useIncrementalCompilation> 
        </configuration> 
       </plugin> 
       <plugin> 
        <groupId>org.codehaus.mojo</groupId> 
        <artifactId>aspectj-maven-plugin</artifactId> 
        <version>1.8</version> 
        <configuration> 
         <!--<showWeaveInfo>true</showWeaveInfo> --> 
         <source>${java.source-target.version}</source> 
         <target>${java.source-target.version}</target> 
         <Xlint>ignore</Xlint> 
         <complianceLevel>${java.source-target.version}</complianceLevel> 
         <encoding>${project.build.sourceEncoding}</encoding> 
         <!--<verbose>true</verbose> --> 
         <!--<warn>constructorName,packageDefaultMethod,deprecation,maskedCatchBlocks,unusedLocals,unusedArguments,unusedImport</warn> --> 
        </configuration> 
        <executions> 
         <execution> 
          <!-- IMPORTANT --> 
          <phase>process-sources</phase> 
          <goals> 
           <goal>compile</goal> 
           <goal>test-compile</goal> 
          </goals> 
         </execution> 
        </executions> 
        <dependencies> 
         <dependency> 
          <groupId>org.aspectj</groupId> 
          <artifactId>aspectjtools</artifactId> 
          <version>${aspectj.version}</version> 
         </dependency> 
        </dependencies> 
       </plugin> 
       <plugin> 
        <groupId>org.codehaus.mojo</groupId> 
        <artifactId>exec-maven-plugin</artifactId> 
        <version>1.4.0</version> 
        <configuration> 
         <mainClass>${main-class}</mainClass> 
        </configuration> 
       </plugin> 
       <plugin> 
        <groupId>org.dstovall</groupId> 
        <artifactId>onejar-maven-plugin</artifactId> 
        <version>1.4.4</version> 
        <executions> 
         <execution> 
          <goals> 
           <goal>one-jar</goal> 
          </goals> 
         </execution> 
        </executions> 
        <configuration> 
         <onejarVersion>0.96</onejarVersion> 
         <mainClass>${main-class}</mainClass> 
         <attachToBuild>true</attachToBuild> 
        </configuration> 
       </plugin> 
      </plugins> 
     </pluginManagement> 
     <plugins> 
      <plugin> 
       <groupId>org.codehaus.mojo</groupId> 
       <artifactId>aspectj-maven-plugin</artifactId> 
      </plugin> 
      <!-- 
      <plugin> 
       <groupId>org.apache.maven.plugins</groupId> 
       <artifactId>maven-compiler-plugin</artifactId> 
      </plugin> 
      --> 
      <plugin> 
       <groupId>org.codehaus.mojo</groupId> 
       <artifactId>exec-maven-plugin</artifactId> 
       <configuration> 
        <mainClass>${main-class}</mainClass> 
        <cleanupDaemonThreads>false</cleanupDaemonThreads> 
       </configuration> 
      </plugin> 
      <plugin> 
       <groupId>org.dstovall</groupId> 
       <artifactId>onejar-maven-plugin</artifactId> 
       <configuration> 
        <mainClass>${main-class}</mainClass> 
       </configuration> 
      </plugin> 
     </plugins> 
    </build> 

    <pluginRepositories> 
     <pluginRepository> 
      <id>OneJAR googlecode.com</id> 
      <url>http://onejar-maven-plugin.googlecode.com/svn/mavenrepo</url> 
     </pluginRepository> 
    </pluginRepositories> 

    <dependencyManagement> 
     <dependencies> 
      <dependency> 
       <groupId>org.aspectj</groupId> 
       <artifactId>aspectjrt</artifactId> 
       <version>${aspectj.version}</version> 
       <scope>runtime</scope> 
      </dependency> 
      <dependency> 
       <groupId>org.seleniumhq.selenium</groupId> 
       <artifactId>selenium-java</artifactId> 
       <version>2.48.2</version> 
      </dependency> 
      <dependency> 
       <groupId>io.github.bonigarcia</groupId> 
       <artifactId>webdrivermanager</artifactId> 
       <version>1.3.0</version> 
      </dependency> 
     </dependencies> 
    </dependencyManagement> 

    <dependencies> 
     <dependency> 
      <groupId>org.aspectj</groupId> 
      <artifactId>aspectjrt</artifactId> 
     </dependency> 
     <dependency> 
      <groupId>org.seleniumhq.selenium</groupId> 
      <artifactId>selenium-java</artifactId> 
     </dependency> 
     <dependency> 
      <groupId>io.github.bonigarcia</groupId> 
      <artifactId>webdrivermanager</artifactId> 
     </dependency> 
    </dependencies> 

    <organization> 
     <name>Scrum-Master.de - Agile Project Management</name> 
     <url>http://scrum-master.de</url> 
    </organization> 

</project> 

Java驅動程序的應用程序:

正如你所看到的,應用程序保存在第二切入點需要WebDriver僅供參考(第一個並不需要它,它可以找到它通過target()綁定)。該Application類也實現Closeable這使我們能夠使用嘗試用資源main方法,確保駕駛員將被關閉outomatically作爲Application實例超出範圍。

package de.scrum_master.app; 

import io.github.bonigarcia.wdm.ChromeDriverManager; 
import org.openqa.selenium.By; 
import org.openqa.selenium.WebDriver; 
import org.openqa.selenium.WebElement; 
import org.openqa.selenium.chrome.ChromeDriver; 

import java.io.Closeable; 
import java.io.IOException; 

public class Application implements Closeable { 
    private final WebDriver driver; 

    public Application() { 
     ChromeDriverManager.getInstance().setup(); 
     driver = new ChromeDriver(); 
    } 

    @Override 
    public void close() { 
     driver.quit(); 
    } 

    public WebDriver getDriver() { 
     return driver; 
    } 

    public void doSomething() { 
     driver.get("http://www.w3schools.com/tags/tryit.asp?filename=tryhtml5_input_type_hidden"); 

     // Button in main frame 
     WebElement button = driver.findElement(By.className("seeResult")); 
     // Text field in iframe 
     driver.findElement(By.name("fname")); 
     // Text area in main frame 
     driver.findElement(By.id("textareaCode")); 
     // Hidden input field in main frame 
     driver.findElement(By.name("bt")); 
     // Hidden input field in iframe 
     WebElement hiddenCountryField = driver.findElement(By.name("country")); 

     // Click button in main frame. This *refreshes* the iframe, making all existing 
     // references to elements therein (e.g. 'hiddenCountryField') stale 
     button.click(); 

     // Get value of hidden input field after iframe refresh 
     System.out.println(driver.findElement(By.name("country")).getAttribute("value")); 

     // This alternative would *not* work because the aspect cannot repair a reference 
     // to an element which is gone forever because the iframe was refreshed 
     // System.out.println(hiddenCountryField.getAttribute("value")); 

     // Click submit button in iframe (triggers both advices) 
     driver.findElement(By.cssSelector("input[type=submit]")).click(); 
    } 

    public static void main(String[] args) { 
     try (Application application = new Application()) { 
      application.doSomething(); 
     } 
    } 
} 

看點:

package de.scrum_master.aspect; 

import de.scrum_master.app.Application; 
import org.openqa.selenium.By; 
import org.openqa.selenium.WebDriver; 
import org.openqa.selenium.WebElement; 

public aspect IFrameSwitcher { 
    WebElement around(WebDriver driver, By by) : 
     !within(IFrameSwitcher) && 
      call(WebElement WebDriver+.findElement(*)) && 
      target(driver) && 
      args(by) 
     { 
      System.out.println(thisJoinPoint + " -> " + by); 
      WebElement webElement; 
      try { 
       System.out.print(" Trying main frame -> "); 
       driver.switchTo().defaultContent(); 
       webElement = proceed(driver, by); 
       System.out.println("OK"); 
       return webElement; 
      } 
      catch (RuntimeException e) { 
       System.out.println(e.getClass().getSimpleName()); 
       for (WebElement iframe : driver.findElements(By.tagName("iframe"))) { 
        try { 
         System.out.print(" Trying iframe " + iframe.getAttribute("id") + " -> "); 
         driver.switchTo().frame(driver.findElement(By.id("iframeResult"))); 
         webElement = proceed(driver, by); 
         System.out.println("OK"); 
         return webElement; 
        } 
        catch (RuntimeException e2) { 
         System.out.println(e2.getClass().getSimpleName()); 
         e = e2; 
        } 
       } 
       throw e; 
      } 
     } 

    void around(Application application, WebElement webElement) : 
     within(Application) && 
     call(void WebElement+.click()) && 
     this(application) && 
     target(webElement) 
    { 
     System.out.println(thisJoinPoint + " -> " + webElement); 
     WebDriver driver = application.getDriver(); 
     try { 
      System.out.print(" Trying main frame -> "); 
      driver.switchTo().defaultContent(); 
      proceed(application, webElement); 
      System.out.println("OK"); 
     } 
     catch (RuntimeException e) { 
      System.out.println(e.getClass().getSimpleName()); 
      for (WebElement iframe : driver.findElements(By.tagName("iframe"))) { 
       try { 
        System.out.print(" Trying iframe " + iframe.getAttribute("id") + " -> "); 
        driver.switchTo().frame(driver.findElement(By.id("iframeResult"))); 
        proceed(application, webElement); 
        System.out.println("OK"); 
        return; 
       } 
       catch (RuntimeException e2) { 
        System.out.println(e2.getClass().getSimpleName()); 
        e = e2; 
       } 
      } 
      throw e; 
     } 
    } 
} 

控制檯日誌:

在這裏你可以看到這兩個切入點火災時,如何失敗的嘗試後,他們會重新啓動等

call(WebElement org.openqa.selenium.WebDriver.findElement(By)) -> By.className: seeResult 
    Trying main frame -> OK 
call(WebElement org.openqa.selenium.WebDriver.findElement(By)) -> By.name: fname 
    Trying main frame -> NoSuchElementException 
    Trying iframe google_ads_iframe_/16833175/TryitLeaderboard_0 -> OK 
call(WebElement org.openqa.selenium.WebDriver.findElement(By)) -> By.id: textareaCode 
    Trying main frame -> OK 
call(WebElement org.openqa.selenium.WebDriver.findElement(By)) -> By.name: bt 
    Trying main frame -> OK 
call(WebElement org.openqa.selenium.WebDriver.findElement(By)) -> By.name: country 
    Trying main frame -> NoSuchElementException 
    Trying iframe google_ads_iframe_/16833175/TryitLeaderboard_0 -> OK 
call(void org.openqa.selenium.WebElement.click()) -> [[ChromeDriver: chrome on XP (5ab9e5f25d169bbc941ab1b08b346c50)] -> class name: seeResult] 
    Trying main frame -> OK 
call(WebElement org.openqa.selenium.WebDriver.findElement(By)) -> By.name: country 
    Trying main frame -> NoSuchElementException 
    Trying iframe google_ads_iframe_/16833175/TryitLeaderboard_0 -> OK 
Norway 
call(WebElement org.openqa.selenium.WebDriver.findElement(By)) -> By.cssSelector: input[type=submit] 
    Trying main frame -> NoSuchElementException 
    Trying iframe google_ads_iframe_/16833175/TryitLeaderboard_0 -> OK 
call(void org.openqa.selenium.WebElement.click()) -> [[ChromeDriver: chrome on XP (5ab9e5f25d169bbc941ab1b08b346c50)] -> css selector: input[type=submit]] 
    Trying main frame -> StaleElementReferenceException 
    Trying iframe google_ads_iframe_/16833175/TryitLeaderboard_0 -> OK 

我希望這可以幫助。請享用!

相關問題