【问题标题】:How can I ask the Selenium-WebDriver to wait for few seconds in Java?如何让 Selenium-WebDriver 在 Java 中等待几秒钟?
【发布时间】:2012-10-03 06:19:25
【问题描述】:

我正在开发 Java Selenium-WebDriver。我加了

driver.manage().timeouts().implicitlyWait(2, TimeUnit.SECONDS);

WebElement textbox = driver.findElement(By.id("textbox"));

因为我的应用程序需要几秒钟来加载用户界面。所以我设置了 2 秒的隐式等待。但我无法找到元素文本框

然后我添加Thread.sleep(2000);

现在它工作正常。哪个是更好的方法?

【问题讨论】:

标签: java selenium selenium-webdriver webdriver


【解决方案1】:

使用Thread.sleep(2000); 是无条件等待。如果您的测试加载速度更快,您仍然需要等待。所以原则上使用implicitlyWait 是更好的解决方案。

但是,我不明白为什么 implicitlyWait 在您的情况下不起作用。您是否测量了findElement 在引发异常之前实际上需要两秒钟。如果是这样,您可以尝试使用this答案中描述的WebDriver的条件等待吗?

【讨论】:

    【解决方案2】:

    嗯,有两种类型的等待:显式等待和隐式等待。 显式等待的想法是

    WebDriverWait.until(condition-that-finds-the-element);
    

    隐式等待的概念是

    driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
    

    您可以了解详情here

    在这种情况下,我更喜欢使用显式等待(尤其是fluentWait):

    public WebElement fluentWait(final By locator) {
        Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
                .withTimeout(30, TimeUnit.SECONDS)
                .pollingEvery(5, TimeUnit.SECONDS)
                .ignoring(NoSuchElementException.class);
    
        WebElement foo = wait.until(new Function<WebDriver, WebElement>() {
            public WebElement apply(WebDriver driver) {
                return driver.findElement(locator);
            }
        });
    
        return  foo;
    };
    

    fluentWait 函数返回您找到的网络元素。 来自fluentWait 的文档: Wait 接口的一个实现,它可以动态配置其超时和轮询间隔。 每个 FluentWait 实例定义等待条件的最长时间,以及检查条件的频率。此外,用户可以将等待配置为在等待时忽略特定类型的异常,例如在页面上搜索元素时的 NoSuchElementExceptions。 详情可获取here

    在您的情况下,fluentWait 的用法如下:

    WebElement textbox = fluentWait(By.id("textbox"));
    

    恕我直言,这种方法更好,因为您不确切知道要等待多少时间,并且在轮询间隔中,您可以设置任意时间值来验证元素的存在。 问候。

    【讨论】:

    • 那是import com.google.common.base.Function;,不是import java.util.function.Function;
    • haventchecked,实际上使用 intelij IDEA 进行开发,它有助于自动导入(在基于 maven 的项目中工作时)
    • 我只是为其他可能想知道正在使用哪个Function 的人大声疾呼。起初对我来说并不明显。感谢您的回答。
    • 或者您可以只使用 lambda 表达式:driver -&gt; driver.findElement(locator)。使用它时,您根本不需要导入语句。
    • 现在是:.withTimeout(Duration.ofSeconds(30)).pollingEvery(Duration.ofSeconds(5)),而不是:.withTimeout(30, TimeUnit.SECONDS).pollingEvery(5, TimeUnit.SECONDS)
    【解决方案3】:

    有时隐式等待似乎被覆盖,等待时间被缩短。 [@eugene.polschikov] 关于原因有很好的文档。我在使用 Selenium 2 进行测试和编码时发现,隐式等待很好,但有时您必须显式等待。

    最好避免直接调用线程休眠,但有时也没有很好的解决方法。但是,还有其他 Selenium 提供的等待选项可以提供帮助。 waitForPageToLoadwaitForFrameToLoad 已被证明特别有用。

    【讨论】:

      【解决方案4】:

      如果使用 webdriverJs (node.js),

      driver.findElement(webdriver.By.name('btnCalculate')).click().then(function() {
          driver.sleep(5000);
      });
      

      上面的代码让浏览器在点击按钮后等待5秒。

      【讨论】:

      • 当问题专门针对 Java 而不是节点/JavaScript 时,您为什么要发布这个?这就像回答如何在 ruby​​ 中做一样题外话。
      • 建议使用 sleep 绝对不是一个好的解决方案
      • @Thor84no 主要是因为我们中的一些人在搜索网络解决方案时找到了这个答案
      【解决方案5】:

      我更喜欢下面的代码等待 2 秒。

      for(int i=0; i<2 && driver.findElements(By.id("textbox")).size()==0 ; i++){
         Thread.sleep(1000);
      }
      

      【讨论】:

        【解决方案6】:

        我喜欢使用自定义条件。这是 Python 中的一些代码:

        def conditions(driver):
            flag = True
            ticker = driver.find_elements_by_id("textbox")
            if not ticker:
                flag = False
            return flag
        
        ... click something to load ...
        self.wait = WebDriverWait(driver, timeout)
        self.wait.until(conditions)
        

        当您需要等待时,您可以通过检查某个元素的存在来明确地执行此操作(此类元素可能因页面而异)。 find_elements_by_id 返回列表 - 是否为空,您只需检查即可。

        【讨论】:

          【解决方案7】:

          点击似乎被阻止? - 如果您使用 WebDriverJS,这是另一种等待方式:

          driver.findElement(webdriver.By.name('mybutton')).click().then(function(){
            driver.getPageSource().then(function(source) {
              console.log(source);
            });
          });
          

          上面的代码在按钮被点击后等待下一页加载,然后抓取下一页的源代码。

          【讨论】:

          • 是什么让代码等待下一页加载?只是回调中的第一个调用是getPageSource吗?
          【解决方案8】:

          这个帖子有点老了,但我想我会发布我目前正在做的事情(正在进行中)。

          虽然我仍然遇到系统负载过重的情况,并且当我单击提交按钮(例如 login.jsp)时,所有三个条件(见下文)都返回 true 但下一页(例如, home.jsp) 尚未开始加载。

          这是一个通用的等待方法,它接受一个 ExpectedConditions 列表。

          public boolean waitForPageLoad(int waitTimeInSec, ExpectedCondition<Boolean>... conditions) {
              boolean isLoaded = false;
              Wait<WebDriver> wait = new FluentWait<>(driver)
                      .withTimeout(waitTimeInSec, TimeUnit.SECONDS)
                      .ignoring(StaleElementReferenceException.class)
                      .pollingEvery(2, TimeUnit.SECONDS);
              for (ExpectedCondition<Boolean> condition : conditions) {
                  isLoaded = wait.until(condition);
                  if (isLoaded == false) {
                      //Stop checking on first condition returning false.
                      break;
                  }
              }
              return isLoaded;
          }
          

          我已经定义了各种可重用的 ExpectedConditions(下面三个)。在此示例中,三个预期条件包括 document.readyState = 'complete'、不存在“wait_dialog”和不存在“spinners”(指示正在请求异步数据的元素)。

          只有第一个可以通用应用于所有网页。

          /**
           * Returns 'true' if the value of the 'window.document.readyState' via
           * JavaScript is 'complete'
           */
          public static final ExpectedCondition<Boolean> EXPECT_DOC_READY_STATE = new ExpectedCondition<Boolean>() {
              @Override
              public Boolean apply(WebDriver driver) {
                  String script = "if (typeof window != 'undefined' && window.document) { return window.document.readyState; } else { return 'notready'; }";
                  Boolean result;
                  try {
                      result = ((JavascriptExecutor) driver).executeScript(script).equals("complete");
                  } catch (Exception ex) {
                      result = Boolean.FALSE;
                  }
                  return result;
              }
          };
          /**
           * Returns 'true' if there is no 'wait_dialog' element present on the page.
           */
          public static final ExpectedCondition<Boolean> EXPECT_NOT_WAITING = new ExpectedCondition<Boolean>() {
              @Override
              public Boolean apply(WebDriver driver) {
                  Boolean loaded = true;
                  try {
                      WebElement wait = driver.findElement(By.id("F"));
                      if (wait.isDisplayed()) {
                          loaded = false;
                      }
                  } catch (StaleElementReferenceException serex) {
                      loaded = false;
                  } catch (NoSuchElementException nseex) {
                      loaded = true;
                  } catch (Exception ex) {
                      loaded = false;
                      System.out.println("EXPECTED_NOT_WAITING: UNEXPECTED EXCEPTION: " + ex.getMessage());
                  }
                  return loaded;
              }
          };
          /**
           * Returns true if there are no elements with the 'spinner' class name.
           */
          public static final ExpectedCondition<Boolean> EXPECT_NO_SPINNERS = new ExpectedCondition<Boolean>() {
              @Override
              public Boolean apply(WebDriver driver) {
                  Boolean loaded = true;
                  try {
                  List<WebElement> spinners = driver.findElements(By.className("spinner"));
                  for (WebElement spinner : spinners) {
                      if (spinner.isDisplayed()) {
                          loaded = false;
                          break;
                      }
                  }
                  }catch (Exception ex) {
                      loaded = false;
                  }
                  return loaded;
              }
          };
          

          根据页面的不同,我可能会使用其中一个或全部:

          waitForPageLoad(timeoutInSec,
                      EXPECT_DOC_READY_STATE,
                      EXPECT_NOT_WAITING,
                      EXPECT_NO_SPINNERS
              );
          

          以下类中还有预定义的 ExpectedConditions:org.openqa.selenium.support.ui.ExpectedConditions

          【讨论】:

          • 很好的答案!我从未见过有人通过方法构造函数传入 ExpectedCondition 项。真是个好主意。 +1
          • Jeff Vincent,你能告诉我这个页面是否会等待 5 分钟,如果是,那么请建议需要发送哪个位置参数?
          • 这是一个很好的答案。我有类似的函数,但是,我必须在每个函数中调用它,以便我的脚本等到页面加载(微调器)。有没有办法可以将这个 waitForSpinner 函数静默地挂接到 ImplicitWait 中,这样我就不需要每次在我的函数中调用它?就像定义函数一样,将其与驱动程序挂钩一次并繁荣。
          【解决方案9】:

          Implicitly wait 和 Thread.sleep 都只用于同步..但不同的是我们可以使用 Implicitly wait for entire program 但 Thread.sleep 仅适用于该单个代码..这里我的建议是使用 Implicitly wait once在程序中,每次你的网页都会被刷新意味着在那个时候使用 Thread.sleep..它会更好:)

          这是我的代码:

          package beckyOwnProjects;
          
          import java.util.concurrent.TimeUnit;
          
          import org.openqa.selenium.By;
          import org.openqa.selenium.WebDriver;
          import org.openqa.selenium.WebElement;
          import org.openqa.selenium.firefox.FirefoxDriver;
          import org.openqa.selenium.interactions.Actions;
          
          public class Flip {
          
              public static void main(String[] args) throws InterruptedException {
                  WebDriver driver=new FirefoxDriver();
                  driver.manage().window().maximize();
                  driver.manage().timeouts().implicitlyWait(2, TimeUnit.MINUTES);
                  driver.get("https://www.flipkart.com");
              WebElement ele=driver.findElement(By.cssSelector(".menu-text.fk-inline-block"));
              Actions act=new Actions(driver);
              Thread.sleep(5000);
              act.moveToElement(ele).perform();
              }
          
          }
          

          【讨论】:

            【解决方案10】:

            隐式等待:在隐式等待期间,如果 Web Driver 由于其可用性而无法立即找到它,WebDriver 将等待提到的时间,并且在指定的时间段内不会再次尝试查找元素。一旦指定的时间结束,它将在抛出异常之前的最后一次尝试再次搜索元素。默认设置为零。一旦我们设置了时间,Web Driver 就会等待 WebDriver 对象实例的周期。

            显式等待:可能会出现特定元素的加载时间超过一分钟的情况。在这种情况下,您绝对不喜欢为隐式等待设置很长的时间,因为如果您这样做,您的浏览器将为每个元素等待相同的时间。 为避免这种情况,您只需在所需元素上单独设置时间即可。通过遵循这一点,您的浏览器隐式等待时间对于每个元素都会很短,而对于特定元素会很长。

            【讨论】:

              【解决方案11】:

              有时隐式等待会失败,说一个元素存在但实际上不存在。

              解决方案是避免使用 driver.findElement 并将其替换为隐式使用显式等待的自定义方法。例如:

              import org.openqa.selenium.NoSuchElementException;
              
              
              public WebElement element(By locator){
                  Integer timeoutLimitSeconds = 20;
                  WebDriverWait wait = new WebDriverWait(driver, timeoutLimitSeconds);
                  try {
                      wait.until(ExpectedConditions.presenceOfElementLocated(locator));
                  }
                  catch(TimeoutException e){
                      throw new NoSuchElementException(locator.toString());
                  }
                  WebElement element = driver.findElement(locator);
                  return element;
              }
              

              除了偶发的、偶然的失败之外,还有其他原因可以避免隐式等待(参见link)。

              您可以像使用 driver.findElement 一样使用这个“元素”方法。 例如:

                  driver.get("http://yoursite.html");
                  element(By.cssSelector("h1.logo")).click();
              

              如果您真的想等待几秒钟以进行故障排除或其他一些罕见的情况,您可以创建类似于 selenium IDE 提供的暂停方法:

                  public void pause(Integer milliseconds){
                  try {
                      TimeUnit.MILLISECONDS.sleep(milliseconds);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }
              

              【讨论】:

                【解决方案12】:
                Thread.sleep(1000);
                

                更糟糕的是:作为静态等待,它会使测试脚本变慢。

                driver.manage().timeouts.implicitlyWait(10,TimeUnit.SECONDS);
                

                这是一个动态等待

                • 在 webdriver 存在之前有效或在驱动程序生命周期之前有一个范围
                • 我们也可以隐式等待。

                最后,我的建议是

                WebDriverWait wait = new WebDriverWait(driver,20);
                wait.until(ExpectedConditions.<different canned or predefined conditions are there>);
                

                有一些预定义的条件:

                isAlertPresent();
                elementToBeSelected();
                visibilityOfElementLocated();
                visibilityOfAllElementLocatedBy();
                frameToBeAvailableAndSwitchToIt();
                
                • 也是动态等待
                • 在这种情况下,等待只需几秒钟
                • 我们必须对要使用的特定 Web 元素使用显式等待。

                【讨论】:

                  【解决方案13】:

                  答案:等待几秒钟,然后使用 Selenium WebDriver 的元素可见性通过以下方法。

                  implicitlyWait() :WebDriver 实例等到整个页面加载完毕。您可以使用 30 到 60 秒来等待整个页面加载。

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

                  ExplicitlyWait WebDriverWait():WebDriver 实例等到整个页面加载完毕。

                  WebDriverWait wait = new WebDriverWait(driver, 60);
                  
                  wait.until(ExpectedConditions.visibilityOf(textbox));
                  
                  driver.findElement(By.id("Year")).sendKeys(allKeys);
                  

                  注意:请使用 ExplicitlyWait WebDriverWait() 来处理任何特定的 WebElement。

                  【讨论】:

                    【解决方案14】:
                    Thread.Sleep(5000);
                    

                    这确实帮助了我,但需要处理 InterruptedException 异常。 所以最好用 try and catch 来包围它:

                    try {
                        Thread.Sleep(5000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    

                    添加 throws 声明:

                    public class myClass {
                        public static void main(String[] args) throws InterruptedException
                        { ... }
                    

                    我更喜欢第二个,因为这样就可以根据需要多次使用sleep(),并避免每次使用sleep() 时都重复trycatch 块。

                    【讨论】:

                      【解决方案15】:

                      使用动作 -

                      用于模拟复杂用户手势的面向用户的 API。

                      参见Actions#pause 方法。

                      【讨论】:

                        猜你喜欢
                        • 2014-12-04
                        • 2013-12-15
                        • 1970-01-01
                        • 2017-07-20
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2018-01-02
                        • 2019-03-07
                        相关资源
                        最近更新 更多