赞
踩
更多关于Selenium的知识请访问CSND论坛“兰亭序咖啡”的专栏:
专栏《Selenium 从入门到精通》
在 UI 自动化时,我们通常需要等待,比如以下场景:
总之,这些等待,对于我们测试的稳定性和正确性非常重要。
最简单的方法是,我们自己写一个While循环不断地检查条件是否满足。
- while(true){
- if(checkCondition()){
- doSomeThing();
- }else{
- Thread.sleep(n秒);
- }
- }
不过这么做不但麻烦,自己实现也容易出错。值得庆幸的是,Selenium 就提供了内置的机制,帮助我们实现等待的功能。
学习中可以造轮子,帮助我们理解原理,但是生产项目中尽量用成熟的轮子。
Selenium 查找元素默认是没有等待的,也就是说找到了就返回WebElement,否则就抛出异常。
我们测试一下,没有配置任何等待:
- @Test
- public void testDefault(){
- WebDriver driver = null;
- long begin = 0;
- try{
- driver = new ChromeDriver();
-
- driver.get("https://mail.163.com");
- begin = System.currentTimeMillis();
- WebElement element = driver.findElement(By.id("inexistence"));
- }finally {
- long end = System.currentTimeMillis();
- log.info("花费时间:{}毫秒", end-begin);
- driver.close();
- }
- }

日志打印:-- 花费时间:100毫秒(这个很短的时间是findElement本身执行遍历dom需要的一些时间)
抛出异常:
org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"css selector","selector":"#inexistence"}
Selenium 提供了等待机制,我们可以通过配置或者调用,很方便的实现我们等待的需求。
Selenium 主要分为:
下面我们分别介绍它们。
隐式等待是全局设置,设置一次后,对整个WebDriver实例生命周期内的所有查找元素操作生效。
它会让Webdriver在寻找元素时,如果元素没有立即找到,就等待一段时间再查找,直到超过设定的最大时间或者找到元素为止。
下面是我们显式等待的测试代码:
- @Test
- public void testImplicit (){
- WebDriver driver = null;
- long begin = 0;
- try{
- driver = new ChromeDriver();
- // 设置隐式等待时间为10秒
- driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
-
- driver.get("https://mail.163.com");
- WebElement element = driver.findElement(By.id("inexistence"));
- }finally {
- long end = System.currentTimeMillis();
- log.info("花费时间:{}毫秒", end-begin);
- driver.close();
- }
- }

其实相对于默认的机制,我们只是加了一行配置的代码:
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
但是效果却非常大:
日志打印:-- 花费时间:10129毫秒(去除方法本身的执行时间,等待时间大于就是10秒)
抛出的异常还是找不到元素:
org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"css selector","selector":"#inexistence"}
当然不是说一定要等待这么久,如果找到了元素,会立刻返回!
等待时间只是超时时间。
简单,一条配置,全局都有效。
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
等待的时间是全局的,但是不同元素、不同页面、甚至不同网络的加载情况不一样,不能对每种元素设置不同的等待时间。
使用不当的话,会对整个测试的效率造成非常大的影响。
比如,我们很多地方会用检查一个元素存不存在,来判断不同的情况。
- Element ele = findElement(XXX);
- if(ele == null){ // 当然默认找不到元素会抛异常而不是为null,不过我们可以使用findElements
- doSometing();
- }else{
- doOtherthing();
- }
如果很多地方都这样检查,那么花费的时间会很长很长!
上面说过,隐式等待是全局一致的,如果我们想更灵活的等待,对一些元素希望等待时间可以短一些,对另一些希望能够多等一些时间,这时显式等待就派上用场了。
- @Test
- public void testExplicitWait(){
- WebDriver driver = null;
- long begin = 0;
- try{
- driver = new ChromeDriver();
-
- driver.get("https://mail.163.com");
- begin = System.currentTimeMillis();
-
- // 等待id为"someId"的元素出现
- WebElement element = new WebDriverWait(driver, Duration.ofSeconds(10))
- .until(ExpectedConditions.presenceOfElementLocated(By.id("someId")));
-
- // 等待加载图标(class为"loading-spinner")消失
- new WebDriverWait(driver, Duration.ofSeconds(10))
- .until(ExpectedConditions.invisibilityOfElementLocated(By.className("loading-spinner")));
-
- }finally {
- long end = System.currentTimeMillis();
- log.info("花费时间:{}毫秒", end-begin);
- driver.close();
- }
- }

可以看到,我们可以对不同的元素设置不同的等待时间
new WebDriverWait(driver, java.time.Duration.ofSeconds(10))
这些wait,其实也是可以复用的,比如10s的等待的Wait,可以被用来检查各种元素。
还能对它们设置不同的条件,比如等待元素的出现、消失
- wait.until(ExpectedConditions.presenceOfElementLocated(By.id("someId")));
- wait..until(ExpectedConditions.invisibilityOfElementLocated(By.className("loading-spinner")));
ExpectedConditions 类内置了常用的各种等待条件,满足我们大部分的场景:
更完整的列表,请查看这个类的方法列表
更精细更灵活的控制:
1. 对不同的元素设置不同的等待时间
2. 对不同的元素设置不同的等待条件
更复杂,维护起来也麻烦。
如果不是很熟悉,乱使用,容易适得其反。
显式等待看上去很强大了,是不是就很完美了呢?
特殊场景下,如果你又更苛刻的要求,你也可以定制化自己的等待,进一步的更精细的控制等待,比如:
- @Test
- public void test() {
- WebDriver driver = null;
- long begin = 0;
- try {
- driver = new ChromeDriver();
-
- driver.get("https://mail.163.com");
- begin = System.currentTimeMillis();
-
- Wait<WebDriver> wait =
- new FluentWait<>(driver)
- .withTimeout(Duration.ofSeconds(2))
- .pollingEvery(Duration.ofMillis(300))
- .ignoring(ElementNotInteractableException.class);
- wait.until(ExpectedConditions.visibilityOfElementLocated(By.className("no-no")));
- } finally {
- long end = System.currentTimeMillis();
- log.info("花费时间:{}毫秒", end - begin);
- driver.close();
- }
- }

更灵活、更精细的控制
太复杂,使用前请认真思考,我们真的需要这么细致的控制吗?
本文介绍了4种等待机制(包括默认的),有了这些等待,可以大大的提高我们测试的准确性和稳定性。这几种机制没有哪个最好,我们需要根据实际的情况选择最合适的等待。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。