Selenium读取DOM时速度极慢

时间:2016-02-17 05:14:39

标签: selenium selenium-webdriver webdriver selenium-firefoxdriver firefox-driver

与DOM的Selenium交互似乎非常缓慢,而在每个页面实例化中做了几件事。在整个网站中,我们都有可见的微调器,表明任何未完成的API调用已解决。总之,我有三种方法可以在执行任何操作之前确保页面的稳定性。

  1. 检查DOM就绪状态
  2. 检查是否有任何未完成的JQuery调用
  3. 检查加载微调器
  4. 所有这三个都是作为页面对象实例化的一部分完成的,具有以下方法。

        public static void waitForLoadingAllSpinnersAnywhere(final WebDriver driver){
        final WebDriverWait wait = new WebDriverWait(driver, timeout);
    
        wait.until(waitForDomReadyState());
        wait.until(waitForjQueryToBeInactive());
        List<WebElement> elements = wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(spinnersLoacator));
    
        for(WebElement element: elements){
            wait.until(invisibilityOfElementLocated(element));  
         }
        }
    
        private static ExpectedCondition<Boolean> waitForDomReadyState(){
    
            return new ExpectedCondition<Boolean>() {
    
                @Override
                public Boolean apply(WebDriver d){
    
                    return ( ((JavascriptExecutor) d).executeScript("return document.readyState;").equals("complete"));
                }
            };
        }
    
    
        private static ExpectedCondition<Boolean> waitForjQueryToBeInactive(){
    
            return new ExpectedCondition<Boolean>() {
    
                @Override
                public Boolean apply(WebDriver d){
    
                    return (Boolean) ( ((JavascriptExecutor) d).executeScript("return jQuery.active == 0;"));
                }
            };
        }
    
        public static ExpectedCondition<Boolean> invisibilityOfElementLocated(final WebElement element){
    
            return new ExpectedCondition<Boolean>() {
    
                @Override
                public Boolean apply(WebDriver driver){
    
                    try{
                        return !element.isDisplayed();
                    } catch (NoSuchElementException | StaleElementReferenceException e){
                        // Returns true because the element is not present in DOM.
                        // The
                        // try block checks if the element is present but is
                        // invisible or stale
                        return true;
                    }
                }
            };
        }
    

    以一个具有大量API调用并获取大量数据的页面(例如患者页面)为例。对于初始类实例化,它需要大约17秒(下面的日志)。我的Selenium知识说,后续的页面实例化不应该花费相同或更多的时间来检查DOM就绪状态,或者JQuery调用或者spinner等待,因为根本没有任何变化。但是,每次新页面实例化时,我都会花费相同的时间来检查所有这三个页面。那里发生了什么? Selenium实际上是在每次执行这些操作时是否尝试与Server交互,或者由于某种原因只是与客户端的交互很慢?如果是这样,可能的答案是什么?

      

    控制台日志

         

    ==== [[完成等待[17]之后在小部件[患者]上找到8个微调器元素]]

         

    ==== [[开始等待在widget [Patient]上找到8个微调元素]]

         

    ==== [[完成等待[17]之后在小部件[患者]上找到8个微调器元素]]

         

    ====浏览器[[[患者]]]

         

    ==== [[开始等待在widget [Patient]上找到8个微调元素]]

         

    ==== [[完成等待[17]之后在小部件[患者]上找到8个微调器元素]]

    环境:

    1. Selenium 2.48
    2. Firefox 38
    3. 我也尝试过使用Selenium 2.52和firefox 44同样的结果

2 个答案:

答案 0 :(得分:2)

您的测试似乎是所有webkit次调用,因此Firefox应该适合您,但我很惊讶Firefox本机调用driver.navigate()甚至可以帮助您进入初始页面,如果您是使用44和48.众所周知,31.6.0是最后支持的原生Firefox版本。所以,我会说你应该使用Chrome,直到你搞清楚。

但是,要回答你关于缓慢的事情。你编写代码的方式,你高度依赖于jQuery,我想你的jQuery代码被调用的问题被延迟,这会传播到你的Selenium测试,并进一步受到循环到多个循环的影响纺纱厂。我之前注意到的一件事是,如果页面忙于运行ajax调用,那么使用JavascriptExecutor进行的Selenium调用可能必须排队等待那些放弃处理器时间的内容。

我会以不同的方式做什么? 好吧,我会写我的微调器等待操作DOM,而不是调用JavascriptExecutors到jQuery。也许在您的情况下,这不是一个选项,但我认为一个经过深思熟虑的计划可以提高您的页面就绪工作流程的效率。

答案 1 :(得分:2)

Selenium处理客户端的所有等待,并在满足条件之前将请求发送到服务器进行每次评估。 它可以在高延迟的情况下快速退化,特别是如果有很多呼叫。此外,一些评估需要脚本注入,这对任何一种都没有帮助。

因此,提高性能的最佳方法是使用单个异步JavaScript调用:

public static void waitForLoadingAllSpinnersAnywhere(final WebDriver driver) {
  const String JS_WAIT_SPINNERS = 
      "var callback = arguments[0]; " +
      "(function fn(){ " +
      "  if (document.readyState == 'complete' && jQuery.active == 0) { " +
      "    var elts = $('.spinners'); " +
      "    if (elts.length == 8 && !elts.is(':visible')) " +
      "      return callback(); " +
      "  } " +
      "  setTimeout(fn, 60); " +
      "})();";

   ((JavascriptExecutor)driver).executeAsyncScript(JS_WAIT_SPINNERS);
}

初始化超时:

driver.manage().timeouts().setScriptTimeout(30, TimeUnit.SECONDS);