Thread.sleep 有效,但隐式等待、webdriverwait 和流畅等待不起作用?

Thread.sleep works but implicit wait, webdriverwait and fluent wait does not?

driver.findElement(By.xpath(sOptionPath)).click();  //this option button changes contents of page   
Thread.sleep(4000);
WebElement combo=driver.findElement(By.xpath(sXpath));
Select dropdownvalue = new Select(combo);
        dropdownvalue.selectByVisibleText(sText);

上面的代码工作正常,但如果我使用 wait 而不是 thread.sleep,我会得到 StaleElementReferenceException 异常。 这是我使用的 Fluent wait :

    Wait<WebDriver> newwait=new FluentWait<WebDriver>(driver).withTimeout(10, TimeUnit.SECONDS).pollingEvery(1, TimeUnit.SECONDS).ignoring(StaleElementReferenceException.class);

        WebElement combo=newwait.until(new ExpectedCondition<WebElement>(){
            @Override
            public WebElement apply(WebDriver driver) {
                return driver.findElement(By.xpath(sXpath));
            }

        });

这找到了组合框,但再次对组合框执行任何操作都会出现 NoSuchElement 或 statestate 异常。所以我也试过这个 select 来自组合框的值:

    Wait<WebElement> elwait=new FluentWait<WebElement>(combo).withTimeout(10, TimeUnit.SECONDS).pollingEvery(1, TimeUnit.SECONDS).ignoring(StaleElementReferenceException.class,NoSuchElementException.class);

        Boolean a=elwait.until(new Function<WebElement,Boolean>(){
            @Override
            public Boolean apply(WebElement arg0) {
                Select dropdownvalue = new Select(arg0);
                dropdownvalue.selectByVisibleText(sText);
                return true;
            }

        });

这会超时并且不起作用!

我怎样才能让它工作,为什么它不工作而 thread.sleep 工作。为什么使用 Thread.sleep 是一种不好的做法?

Thread.sleep 是一种不好的做法,因为您使用的是硬编码等待。即使该元素在 1 秒内出现,您也不必再等待 3 秒。或者,假设元素在 10 秒后出现。你等待 4 秒,之后你会得到一个异常,没有这样的元素存在。所以使用更可靠的预期条件。 Thread.sleep 不可靠。 https://selenium.googlecode.com/git/docs/api/java/org/openqa/selenium/support/ui/ExpectedConditions.html

WebDriverWait wait = new WebDriverWait(driver, timeout);
wait.until(ExpectedConditions.elementToBeClickable(By.xpath(sXpath)));

WebElement combo=driver.findElement(By.xpath(sXpath));
Select dropdownvalue = new Select(combo);
dropdownvalue.selectByVisibleText(sText);

我会尝试使用 ExpectedCondtions class.

中的一些现有检查来验证我返回到 'combo' 的对象是否过时
   Wait<WebDriver> newwait=new FluentWait<WebDriver>(driver).withTimeout(10, TimeUnit.SECONDS).pollingEvery(1, TimeUnit.SECONDS).ignoring(StaleElementReferenceException.class);

        WebElement combo=newwait.until(new ExpectedCondition<WebElement>(){
            @Override
            public WebElement apply(WebDriver driver) {
                WebElement found = driver.findElement(By.xpath(sXpath));
                if (ExpectedConditions.stalenessOf(found).apply(driver)) {
                    return null;
                }
                return found;
            }

        });

我正在使用 2.47.2 版本,当从委托函数返回 null 时,FluentWait 似乎会重试,所以我希望它能重试,否则你会得到 StaleElementException。

 public <V> V until(Function<? super T, V> isTrue) {
    long end = clock.laterBy(timeout.in(MILLISECONDS));
    Throwable lastException = null;
    while (true) {
      try {
        V value = isTrue.apply(input);
        if (value != null && Boolean.class.equals(value.getClass())) {
          if (Boolean.TRUE.equals(value)) {
            return value;
          }
        } else if (value != null) {
          return value;
        }
      } catch (Throwable e) {
        lastException = propagateIfNotIngored(e);
      }

      // Check the timeout after evaluating the function to ensure conditions
      // with a zero timeout can succeed.
      if (!clock.isNowBefore(end)) {
        String toAppend = message == null ?
            " waiting for " + isTrue.toString() : ": " + message;

        String timeoutMessage = String.format("Timed out after %d seconds%s",
            timeout.in(SECONDS), toAppend);
        throw timeoutException(timeoutMessage, lastException);
      }

      try {
        sleeper.sleep(interval);
      } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        throw new WebDriverException(e);
      }
    }

我在我的一个测试中看到了类似的东西,这花了我一段时间,但我最终得出结论,在我的例子中,这是 WebDriver 配置中的隐式等待和显式等待之间的竞争条件时间。我还没有进行证明这种情况的测试,但这是我目前的理论......

睡觉

  1. 执行任务以刷新 dom
  2. 睡眠——在此期间dom刷新
  3. 重新请求刷新对象dom
  4. 测试按预期继续。

显式等待 <= 隐式等待

  1. 执行任务以刷新 dom
  2. 显式等待触发(10 秒),抓取 dom 并尝试获取元素(隐式等待 30 秒)
  3. Dom刷新
  4. 显式等待在 10 秒后结束。它只尝试一次根据原始 DOM
  5. 解析对象
  6. 测试失败

显式等待 > 隐式等待

  1. 执行任务以刷新 dom
  2. 显式等待触发(30 秒),抓取 dom 并尝试获取元素(隐式等待 10 秒)
  3. Dom刷新
  4. 10 秒后第一个请求失败,dom 刷新
  5. 显式等待尝试获取元素,并且成功
  6. 测试继续。

基于这个假设,我最近没有看到这个问题。我使我的测试可以访问隐式等待值,现在我可以根据我要执行的重试次数计算时间范围。

private final WebElement explicitWait(int retries, Predicate<Boolean> test) {
        WebDriverWait wait = new WebDriverWait(driver, retries * getImplicitWait());
        return wait.until(test);
}

我完全同意 Vinoth 关于 Thread.sleep 的使用和可靠性的观点,它是不可靠的,如果在大量测试中经常出现它会造成浪费。最好有一种机制可以尽快响应并考虑类型正确且有意义的异常。

祝你好运。