zoukankan      html  css  js  c++  java
  • Selenium等待:sleep、隐式、显式和Fluent

    Selenium等待页面加载在Selenium自动化测试中起着重要的作用。它们有助于使测试用例更加稳定,增强健壮性。Selenium提供多种等待,根据某些条件在脚本执行相应的等待,从而确保Selenium执行自动化测试时不会导致脚本失败。

    在本文中,我们将介绍Selenium等待和睡眠的类型,并提供演示Demo以及对它们的比较分析。

    为什么需要等待

    大多数应用程序的前端都是基于JavaScriptAjax构建的,使用诸如ReactAngularVue之类的框架,都是需要花费一定时间才能在页面上加载或刷新Web元素。因此,如果测试用例在脚本中找到尚未加载到页面上的元素,则Selenium会向抛出ElementNotVisibleException的异常。

    下面的代码片段将展示与使用Selenium执行自动化测试时的问题。在此代码段中,使用的是某一航空订票网站的示例,在该示例中,post用户选择行程日期的FromTo目的地,Web应用程序需要花费一些时间来加载所需的航班详细信息。在正常用户使用情况下,可以从列表中预订某一班航班。现在,由于页面尚未完全加载,测试脚本无法找到立即预订按钮。结果抛出NoSuchElementException异常。下面的代码段和控制台输出:

    import java.util.concurrent.TimeUnit;
    
    import org.openqa.selenium.By;
    import org.openqa.selenium.JavascriptExecutor;
    import org.openqa.selenium.Keys;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.chrome.ChromeDriver;
    
    import com.gargoylesoftware.htmlunit.javascript.background.JavaScriptExecutor;
    
    public class NoWaitImplemented {
    
        public static void main(String[] args) throws InterruptedException {
            System.setProperty("webdriver.chrome.driver", ".\Driver\chromedriver.exe");
            WebDriver driver=new ChromeDriver();
            driver.manage().window().maximize();
            driver.get("https://www.***.com/");
            driver.findElement(By.id("FromSector_show")).sendKeys("北京", Keys.ENTER);
            driver.findElement(By.id("Editbox13_show")).sendKeys("上海", Keys.ENTER);
            driver.findElement(By.id("ddate")).click();
            driver.findElement(By.id("snd_4_08/08/2020")).click();
            driver.findElement(By.className("src_btn")).click();
            driver.findElement(By.xpath("//button[text()='立即预定']")).click();
       }
    
    }
    

    控制台输出:

    
    *** Element info: (Us ing=xpath, value=//button(text()='立即预定']
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance (Unknown Source )
    at sun.reflect.DelegatingConstructorAcces sorImp1.newInstance (Unknown Source )
    at java.lang.reflect.Constructor.newInstance (Unknown Source )
    at org.openqa.selenium.remote.http.W3CHttpResponseCodec.createException(W3CHttpResponseCodec.java:187)at org.openqa.selenium.remote.http.W3CHttpResponseCodec.decode (W3CHttpResponseCodec.java:122)
    at org.openqa.selenium.remote.http.W3CHttpResponseCodec.decode (W3CHttpResponseCodec.java:49)
    at org.openqa.selenium.remote.HttpC ommandExecutor.execute (HttpC ommandExecutor.java:158)
    at org.openqa.selenium.remote.service.DriverCommandExecutor.execute(DriverCommandExecutor.java:83)at org.openqa.selenium.remote.RemoteWebDriver.execute ( RemoteWebDriver.java:
    
    

    Selenium等待页面加载有助于解决此问题。Selenium等待有不同类型,例如隐式等待显式等待,可确保在Selenium脚本执行元素定位之前,页面元素加载到页面中以进行进一步的操作。

    Selenium等待

    在使用Selenium执行自动化测试时,在编写Selenium脚本时,我们使用以下类型的等待:

    • Thread.Sleep()方法
    • 隐式等待
    • 显式等待
    • Fluent等待

    Thread.Sleep()方法

    Thread.Sleep()是属于线程类的静态方法。可以使用类名(即Thread)的引用来调用此方法。如果在使用Selenium执行自动化测试时使用Thread.Sleep(),则此方法将在指定的时间段内停止执行脚本,而不管是否在网页上找到了该元素。Thread.Sleep()方法中时间参数的单位是毫秒。相同的语法是:

    Thread.sleep(3000);

    睡眠函数抛出InterruptedException,因此应使用try-catch块进行处理,如下所示

            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                logger.error("error", e);
            }
    

    Thread.Sleep()不是好主意

    下面我将重点介绍使用Thread.Sleep()的一些缺点。

    使用Thread.Sleep()方法Selenium Webdriver等待指定的时间,无论是否找到对应元素。如果在指定的持续时间之前找到元素,脚本将仍然等待持续的时间,从而增加了脚本的执行时间。如果花费的时间超过了定义的时间,脚本将抛出错误。这就是为什么使用Selenium处理动态元素,那么最好不要使用Thread.Sleep()

    下面的代码片段突出显示了Thread.Sleep()Selenium自动化测试中的用法。

    import java.util.concurrent.TimeUnit;
    
    import org.openqa.selenium.By;
    import org.openqa.selenium.JavascriptExecutor;
    import org.openqa.selenium.Keys;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.chrome.ChromeDriver;
    
    import com.gargoylesoftware.htmlunit.javascript.background.JavaScriptExecutor;
    
    public class ThreadWait {
    
        public static void main(String[] args) throws InterruptedException {
            System.setProperty("webdriver.chrome.driver", ".\Driver\chromedriver.exe");
            WebDriver driver=new ChromeDriver();
            driver.manage().window().maximize();
            driver.get("https://www.***.com/");
            
            driver.findElement(By.id("FromSector_show")).sendKeys("北京", Keys.ENTER);
            driver.findElement(By.id("Editbox13_show")).sendKeys("上海", Keys.ENTER);
            driver.findElement(By.id("ddate")).click();
            driver.findElement(By.id("snd_4_08/08/2020")).click();
            driver.findElement(By.className("src_btn")).click();
            Thread.sleep(5000);
            driver.findElement(By.xpath("//button[text()='立即预定']")).click();
    
        }
    
    }
    

    如果不使用Thread.sleep(),那么哪个Selenium等待页面加载就足以满足测试要求?在这种情况下,这就需要隐式等待来处理。

    隐式等待

    Selenium解决了Thread.Sleep()存在的问题,并提出了两个Selenium等待页面加载的方法。其中之一是隐式等待,它允许您将WebDriver暂停特定的时间,直到WebDriver在网页上找到所需的元素为止。

    这里要注意的关键点是,与Thread.Sleep()不同,它不需要等待整个时间段。如果在指定的持续时间之前找到元素,将继续执行下一行代码,从而减少了脚本执行的时间。这就是为什么隐式等待也称为动态等待的原因。如果在指定的持续时间内未找到该元素,则抛出ElementNotVisibleException

    关于隐式等待的另一件值得注意的事情是,它是全局应用的,这使其比Thread.Sleep()更好。这意味着测试人员只需编写一次即可,它适用于整个WebDriver实例中脚本上指定的所有Web元素。是不是特别方便?实现相同的语法是:

    driver.manage().timeouts().implicitlyWait(Time Interval to wait for, TimeUnit.SECONDS);

    隐式等待的默认时间为,并且每隔500毫秒会不断轮询所需的元素。让我们看下面的代码片段,展示隐式等待的用法。在此示例中,我使用了相同的订票网站示例。在这种情况下,我们将进行预订过程,在此过程中页面需要花费更多的时间来加载。在这里,存在两个页面的页面加载问题,我们使用Thread.Sleep()而不是多次使用Thread.Sleep()来处理一行代码。

    import java.util.concurrent.TimeUnit;
    
    import org.openqa.selenium.By;
    import org.openqa.selenium.JavascriptExecutor;
    import org.openqa.selenium.Keys;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.WebElement;
    import org.openqa.selenium.chrome.ChromeDriver;
    import org.openqa.selenium.support.ui.Select;
    
    import com.gargoylesoftware.htmlunit.javascript.background.JavaScriptExecutor;
    
    public class ImplicitWait {
    
        public static void main(String[] args) throws InterruptedException {
    
            System.setProperty("webdriver.chrome.driver", ".\Driver\chromedriver.exe");
            WebDriver driver=new ChromeDriver();
            driver.manage().window().maximize();
            driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
            driver.get("https://www.***.com/");
            
            driver.findElement(By.id("FromSector_show")).sendKeys("北京", Keys.ENTER);
            driver.findElement(By.id("Editbox13_show")).sendKeys("上海", Keys.ENTER);
            driver.findElement(By.id("ddate")).click();
            driver.findElement(By.id("snd_4_08/08/2020")).click();
            driver.findElement(By.className("src_btn")).click();
           driver.findElement(By.xpath("//button[text()='立即预定']")).click();
            
            JavascriptExecutor jse = (JavascriptExecutor)driver;
            jse.executeScript("window.scrollBy(0,750)");
            
            driver.findElement(By.xpath("//input[@type='email']")).sendKeys("***@FunTester.com");
            driver.findElement(By.xpath("//span[text()='继续']")).click();
            WebElement title=driver.findElement(By.id("titleAdult0"));
            Select titleTraveller=new Select(title);
            titleTraveller.selectByVisibleText("MS");
            driver.findElement(By.xpath("//input[@placeholder='Enter First Name']")).sendKeys("FunTester");
            driver.findElement(By.xpath("//input[@placeholder='Enter Last Name']")).sendKeys("FunTester");
            driver.findElement(By.xpath("//input[@placeholder='Mobile Number']")).sendKeys("*********");
            driver.findElement(By.xpath("//div[@class='con1']/span[@class='co1']")).click();
            }
    
    }
    

    我们知道了一个事实,即应该在一定的持续时间内加载页面,但是如果我们不知道在加载时该元素是可见/可点击的,该怎么办?正如它出现的时候一样,元素是动态的,并且可能会不时地变化。在这种情况下,显式等待将帮助解决此问题。让我们看一下显示等待的细节。

    显示等待

    显式等待是动态Selenium等待的另外一种类型。显式等待帮助可在特定时间段内根据特定条件停止脚本的执行。时间到了以后,脚本将抛出ElementNotVisibleException异常。在测试人员不确定要等待的时间的情况下,显式等待会派上大用场。使用elementToBeClickable()textToBePresentInElement()之类的条件,可以等待指定的持续时间。可以结合使用WebDriverWaitExpectedConditions类来使用这些预定义方法。为了使用这种情况,请在代码中导入以下软件包:

    import org.openqa.selenium.support.ui.ExpectedConditions
    import org.openqa.selenium.support.ui.WebDriverWait
    

    添加该代码后,需要为WebDriverWait类创建一个引用变量,并使用WebDriver实例实例化该变量,并提供可能需要的Selenium等待页面加载的数量。时间单位是秒。可以如下定义它:

    WebDriverWait wait = new WebDriverWait(driver,30);

    为了使用ExpectedCondition类的预定义方法,我们将使用如下的wait引用变量:

    wait.until(ExpectedConditions.visibilityOfElementLocated());

    预期条件的类型

    以下是在使用Selenium执行自动化测试时通常使用的几种预期条件。

    • visibleOfElementLocated():验证给定元素是否存在
    • alertIsPresent():验证是否存在警报。
    • elementToBeClickable():验证给定元素是否在屏幕上存在/可单击
    • textToBePresentInElement():验证给定元素是否具有必需的文本
    • titlels():验证条件,等待具有给定标题的页面

    还有更多可用的预期条件,您可以通过Selenium官方GitHub页面进行引用。与隐式等待一样,显式等待也会在每500毫秒后继续轮询。

    下面是显示等待Selenium中用法的代码段。在此示例中,我们使用的是订票网站,其中的模式在动态时间显示在主页上。使用显式等待,基于元素的可见性,我们将等待元素并关闭弹出窗口。

    参考代码:

    import java.util.concurrent.TimeUnit;
    
    import org.openqa.selenium.By;
    import org.openqa.selenium.JavascriptExecutor;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.chrome.ChromeDriver;
    import org.openqa.selenium.support.ui.ExpectedConditions;
    import org.openqa.selenium.support.ui.WebDriverWait;
    
    public class ExplicitWait {
    
        public static void main(String[] args) {
                    System.setProperty("webdriver.chrome.driver", ".\Driver\chromedriver.exe");
                    WebDriver driver=new ChromeDriver();
                    driver.manage().window().maximize();
                    
                    driver.get("https://www.*****.com/");
                    
                    driver.findElement(By.xpath("//span[@class='rm-city__selectorBoxLoca'][contains(text(),'北京')]")).click();
                    WebDriverWait wait=new WebDriverWait(driver, 120);
                    wait.until(ExpectedConditions.visibilityOf(driver.findElement(By.xpath("//div[@class='Campaign__innerWrapper']/button"))));
                    driver.findElement(By.xpath("//div[@class='Campaign__innerWrapper']/button")).click();
    
        }
    
    }
    
    • 注意:当同时使用隐式等待显式等待时,它们等待的时间是累计的,而不是在单个等待条件下工作。例如,如果给定隐式等待30秒,给定显式等待10秒,那么它正在寻找的显式元素将等待40秒

    显式等待与隐式等待

    现在各位已经知道隐式等待显式等待的用法,因此让我们看一下一下这两个Selenium等待之间的区别:

    隐式等待 显式等待
    默认情况下应用于脚本中的所有元素。 仅适用于特定条件的特定元素。
    不能基于指定条件(例如元素选择/可点击)而不是显式地等待。 可以根据特定条件指定等待时间。
    确定该元素在特定时间内可能可见时,通常使用它 不知道元素可见性的时间时,通常使用它。它具有动态性质。

    Fluent等待

    就其本身功能而言,Fluent等待类似于显式等待。在Fluent等待中,当测试人员不知道某个元素可见或单击所需的时间时,而需要对其执行Selenium等待。Fluent等待提供的一些差异因素:

    • 轮询频率:在显式等待的情况下,默认情况下此轮询频率为500毫秒。使用Fluent wait,测试工程师可以根据需要更改此轮询频率。
    • 忽略异常:在轮询期间,如果找不到元素,则可以忽略任何异常,例如NoSuchElement异常等。
    • 除了这些差异因素(例如显式等待或隐式等待)之外,Fluent还可以定义等待元素可见或可操作的时间。以下语法或代码行用于定义Selenium中的Fluent等待:
            Wait<WebDriver> fluentWait = new FluentWait<WebDriver>(driver)
                    .withTimeout(60, SECONDS) // 自定义等待的总时间
                    .pollingEvery(2, SECONDS) // 自定义轮询频率
                    .ignoring(NoSuchElementException.class); //  自定义要忽略的异常
            WebElement foo = fluentWait.until(new Function<WebDriver, WebElement>() {
                public WebElement apply(WebDriver driver)  // 自定义等待条件
                {
                    return driver.findElement(By.id("FunTester"));
                }
            });
    

    咋一看语法似乎很复杂,但是一旦开始学习使用,熟练之后,Fluent会变得很方便。这是测试人员选择显式等待而不是Fluent等待的最大原因之一。另外,显式等待Fluent等待之间的主要区别在于显式等待提供了预定义的条件,这些条件适用于我们需要等待的元素,而对于Fluent Selenium等待,则可以自定义适用方法中的条件。


    公众号FunTester首发,原创分享爱好者,腾讯云和掘金社区首页推荐,知乎七级原创作者,欢迎关注、交流,禁止第三方擅自转载。

    FunTester热文精选

  • 相关阅读:
    C语言 realloc为什么要有返回值,realloc返回值具体解释/(解决随意长度字符串输入问题)。
    opencv中的vs框架中的Blob Tracking Tests的中文注释。
    Java实现 蓝桥杯VIP 算法提高 棋盘多项式
    Java实现 蓝桥杯VIP 算法提高 棋盘多项式
    Java实现 蓝桥杯VIP 算法提高 棋盘多项式
    Java实现 蓝桥杯VIP 算法提高 棋盘多项式
    Java实现 蓝桥杯VIP 算法提高 分苹果
    Java实现 蓝桥杯VIP 算法提高 分苹果
    Java实现 蓝桥杯VIP 算法提高 分苹果
    Java实现 蓝桥杯VIP 算法提高 分苹果
  • 原文地址:https://www.cnblogs.com/FunTester/p/13736112.html
Copyright © 2011-2022 走看看