【问题标题】:Thread.sleep works but implicit wait, webdriverwait and fluent wait does not?Thread.sleep 有效,但隐式等待,webdriverwait 和流利等待不?
【发布时间】:2015-10-06 19:05:23
【问题描述】:
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<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 异常。所以我也试过这个从组合框中选择值:

    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 是一种不好的做法?

【问题讨论】:

    标签: java selenium-webdriver wait


    【解决方案1】:

    我会尝试使用来自 ExpectedCondtions 类的一些现有检查来验证我返回到“组合”的对象是否过时。

       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. sleep -- 在此期间 dom 刷新
    3. 从刷新 dom 重新请求对象
    4. 测试按预期继续。

    显式等待

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

    显式等待 > 隐式等待

    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 的使用和可靠性的观点,它不可靠,如果在大量测试中过于频繁地出现,可能会造成浪费。最好有一种机制能够尽快响应并解决类型良好且有意义的异常。

    祝你好运。

    【讨论】:

    • 这对我来说效果很好,直到最近这再次开始在相同的代码中给出 staleElementException ,即使在从提到的示例中检查了 (found) 的陈旧性之后也是如此。然后我再次使用预期条件检查组合上的陈旧元素,它超时了。不知道是什么导致了这种不稳定的行为
    • 无法重现确切的情况很难说,但听起来您已经能够在底层刷新发生之前解析 web 元素。我还没有看到这种行为。您可以尝试减慢 WebDriverWait 的轮询间隔以分配更多时间进行刷新? wait.pollEvery(long, TimeUnit).
    • 让我感到困惑的是,如果我只是在开始时放置一个甚至 1s 的 thread.sleep,一切都像魅力一样。页面中也没有ajax。
    • 另一种可能性可能是您如何使用已解析的 WebElement。例如,如果您有一个 50 行的方法,并且您在第 2 行解析引用,但在第 48 行使用它,那么 DOM 有时间刷新并且您失去了钩子。这是 PageFactory 可以协助的事情之一,因为(默认情况下)PageFactory WebElement 是按需解析的。您可以通过每次要使用它时基本上解析 WebElement 来模拟它。在上面的示例中,如果您解析在线 2 并在第 3 行使用它,那么按需查找可能无济于事。
    • 我的代码在提到的示例之后的下一行是创建一个 Select 对象并在 next 中使用它。它正在工作,但突然停止工作,开发也没有任何变化。我实际上无法了解到底发生了什么。现在我已经放了一个 thread.sleep(1000) 以防我在创建和使用 Select 对象时得到一个 staleelementreference ezception
    【解决方案2】:

    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);
    

    【讨论】:

      猜你喜欢
      • 2012-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-19
      • 2019-01-04
      • 1970-01-01
      • 1970-01-01
      • 2012-08-15
      相关资源
      最近更新 更多