Selenium-这样混合隐式等待和显式等待可以吗?

问题描述 投票:1回答:3

这里是udemy course(来自“ Lets Kode It”),用于开发使用硒和Java的Web自动化框架。 但是,这不是Java问题。您只需要了解以下任何一种语言中的硒-javascript,python,ruby,c#和java。

讲师开发了一个CustomDriver类,该类具有以下给出的方法/功能。该方法等待元素可单击,而不必在我们的代码中到处编写WebDriverWait语句。它首先将隐式等待设置为零,然后进行显式等待,然后将隐式等待设置为框架中使用的原始值。

这种方法对我来说似乎还可以,但我不确定。这样混合隐式等待和显式等待会导致任何问题吗?

/*
 Click element when element is clickable
 @param locator - locator strategy, id=>example, name=>example, css=>#example,
                       tag=>example, xpath=>//example, link=>example
 @param timeout - Duration to try before timeout
 */
public void clickWhenReady(By locator, int timeout) {
    try {
        driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS);
        WebElement element = null;
        System.out.println("Waiting for max:: " + timeout + " seconds for element to be clickable");

        WebDriverWait wait = new WebDriverWait(driver, 15);
        element = wait.until(
                ExpectedConditions.elementToBeClickable(locator));
        element.click();
        System.out.println("Element clicked on the web page");
        driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
    } catch (Exception e) {
        System.out.println("Element not appeared on the web page");
        driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
    }
}
selenium selenium-webdriver webdriverwait
3个回答
0
投票

我不建议混合使用。由于Implicit wait通常是在WebDriver系统的remote端实现的,这意味着它们是在基于浏览器的驱动程序(例如chromedriver.exe,IEDriverServer.exe)中处理的,而Explicit Wait是在本地语言绑定,例如Java,ruby,python等。

下面是典型示例,用remote server运行脚本时会发生什么。

本地代码->远程服务器->远程服务器上的本地语言绑定->远程组件,例如chromedriver.exe或IEDriverServer.exe。如果涉及到网格,事情就会变得更加复杂,因为它可能是链之间的另一层。

因此,当您同时使用隐式等待和显式等待时,可能会出现不确定的行为。而且,由于隐式等待是在驱动程序级别实现的,因此它们随时可能更改,并且会对脚本产生影响。因此,最好始终坚持明确等待并完全控制。

使用当前技术,元素可能会在元素出现后立即渲染。因此,仅使用implicit wait是不够的,因此强烈希望使用explicit wait。在某些情况下,我们可能必须使用implicit wait,但如果您打算将来扩展脚本以在网格上/使用远程服务器运行,则切勿将两者混用。


0
投票

您实际上并没有同时混合两种不同的等待类型。但是是的,您的代码不是很好。请看下面我长期以来一直在使用的代码(我给您的想法),并成功地对正/负方案执行测试。您可以使用“ finally”来确保隐式返回到分配的等待时间。

 public static void waitForElementToBeClickableByLocator(WebDriver driver, By locator) {
            try {
                driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS);
                wait = new WebDriverWait(driver, 30)
                        .ignoring(NoSuchElementException.class, StaleElementReferenceException.class)
                        .pollingEvery((Duration.ofSeconds(SECONDS));
                wait.until(ExpectedConditions.elementToBeClickable(locator));
                Log.info("Element is clickable");
            } 
catch (Exception e) {
                Log.error(e.getMessage());
                Assert.fail("Element is not clickable by locator: " + locator);
            } 
finally {
                driver.manage().timeouts().implicitlyWait(Constants.implicitWaitTime, TimeUnit.SECONDS);
            }
        }

0
投票

使用隐式等待和显式等待的问题归结为Selenium源代码中如何实现ExpectedConditions的缺陷。

让我通过分析以下代码来解释问题:

WebDriver driver = new ChromeDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
WebElement element =  new WebDriverWait(driver, 5, 1000).until(ExpectedConditions.elementToBeClickable(By.id("some_id")));
  1. 我们初始化驱动程序并将隐式等待时间设置为10秒。这意味着driver.findElement()将等待10秒,直到找到元素为止,然后才抛出NoSuchElementException这是要注意的非常重要的一点
  2. 然后,我们设置了一个明确的等待时间,持续时间为5秒,在轮询1000毫秒(1秒)之间的睡眠时间。这意味着WebDriverWait将每1秒至5秒轮询一次ExpectedConditions为真。如果ExpectedConditions返回true,则轮询将停止,并返回ExpectedConditions中指定的对象。在上面的示例代码中,返回的对象为WebElement。如果5秒钟后ExpectedConditions为假,则抛出TimeoutException或我们期望)。现在该看看ExpectedConditions中发生了什么。
  3. ExpectedConditions.elementToBeClickable()代码具有以下语法。

    public static ExpectedCondition<WebElement> elementToBeClickable(final By locator) {
        return new ExpectedCondition<WebElement>() {
            @Override
            public WebElement apply(WebDriver driver) {
                WebElement element = visibilityOfElementLocated(locator).apply(driver);
                try {
                    if (element != null && element.isEnabled()) {
                        return element;
                    }
                    return null;
                } catch (StaleElementReferenceException e) {
                    return null;
                }
            }
        };
    }
    
  4. 上面的elementToBeClickable依次调用visibilityOfElementLocated()方法以确认元素是否可见。

    public static ExpectedCondition<WebElement> visibilityOfElementLocated(final By locator) {
        return new ExpectedCondition<WebElement>() {
            @Override
            public WebElement apply(WebDriver driver) {
                try {
                    return elementIfVisible(driver.findElement(locator));
                } catch (StaleElementReferenceException e) {
                    return null;
                }
            }
        };
    }
    

    5。注意上面在driver.findElement(locator)方法中如何调用visibilityOfElementLocated()。如果找不到该元素,则将隐式等待10秒。因此,驱动程序将等待10秒钟,直到它抛出NoSuchElementException

但请等待(双关语不是故意的!在elementToBeClickable()条件下,我们的显式等待是否设置为在5秒后超时?是的,但是隐式等待将首先应用。 WebDriverWait将捕获NoSuchElementException并在10秒后抛出TimeoutException,而不是设置的显式等待5秒。这就是问题中的解决方案试图解决的问题。解决方案尝试将隐式等待设置为0秒,以便正确执行显式等待条件,然后重置隐式等待。

课题中提供的实施确实完成了工作,没有一个细节。隐式等待被硬编码为3秒,这是不理想的。您如何将隐式等待作为全局通用常量来提供是特定于案例的。我们正在对驱动程序设置隐式等待,我们可以期望像“ driver” driver.manage().timeouts().getImplicitWait()这样的隐式等待。虽然很理想,但是不幸的是这不可能直接实现。有解决方法,@ forresthopkinsa在创建用于获取隐式等待的扩展驱动程序方面有一个不错的interesting solution

© www.soinside.com 2019 - 2024. All rights reserved.