Selenium有几种等待方式,并给出使用场景

前言

这些是过去学习和工作中积累的个人总结,不过可能会存在一些主观臆断,如果有说错的地方,请指出来哦!

回答

在Selenium中提供了四种等待方式,分别是强制等待,隐式等待,显示等待以及FluentWait等待。

强制等待
  • 原理:强制等待,线程休眠一定时间

  • 优缺点

    • 优点:简单
    • 缺点:不能准确把握等待的时间(有点浪费时间),影响执行速度
  • 使用方法:Thread.sleep(x),等待x毫秒后,进行下一步操作

  • 使用场景:脚本调试,脚本编写

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;


public class ElementWait {
    private static WebDriver driver;

    // 前置条件 driver实例化
    @BeforeAll
    static void setUP() {
        System.setProperty("webdriver.chrome.driver", "/Users/wangtao/TestTools/Java/SeleniumCase/src/main/resources/ChromeDriver/chromedriver");
        driver = new ChromeDriver();
    }

    // 后置操作 浏览器退出
    @AfterAll
    static void tearDown() {
        driver.quit();
    }

    //测试步骤
    @Test
    public void locatorByID() throws InterruptedException {
        // 打开浏览器
        driver.get("https://www.baidu.com/");
        // 窗口最大化
        driver.manage().window().maximize();
        // 根据partialLinkText定位的方式,定位到新闻元素,并且点击
        driver.findElement(By.id("kw")).sendKeys("测试论坛");
        // 强制等待2000毫秒(2秒)
        Thread.sleep(2000);
    }
}
隐式等待
  • 原理:设置一个等待时间,轮询查找(默认0.5秒)元素是否出现,如果没有出现就抛出异常

  • 优缺点

    • 优点:只需要在整个driver生命周期中设置一次即可
    • 缺点:如果找不到元素,就不管了。只关注元素能不能找到,不关注元素能否点击或者进行其他的交互。相对而言,效率会受到影响。必须等到页面加载策略实现以后,才会开始执行
  • 使用方法:driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));

  • 使用场景:可解决找不到元素问题,但无法解决交互问题

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;

import java.time.Duration;


public class ElementWait {
    private static WebDriver driver;

    // 前置条件 driver实例化
    @BeforeAll
    static void setUP() {
        System.setProperty("webdriver.chrome.driver", "/Users/wangtao/TestTools/Java/SeleniumCase/src/main/resources/ChromeDriver/chromedriver");
        driver = new ChromeDriver();
    }

    // 后置操作 浏览器退出
    @AfterAll
    static void tearDown() {
        driver.quit();
    }

    //测试步骤
    @Test
    public void locatorByID() throws InterruptedException {
        // 打开浏览器
        driver.get("https://vip.ceshiren.com//");
        // 窗口最大化
        driver.manage().window().maximize();
        
        driver.findElement(By.xpath("//*[text()='个人中心']"));
    }
}
显示等待
  • 原理:在最长等待时间内,是否满足结束条件

  • 优缺点

    • 优点:更精确的等待,脚本更灵活以及稳定性更好
    • 缺点:增加代码复杂性以及依赖性
  • 使用方法:WebDriverWait(driver实例, 最长等待时间).until(结束条件);

  • 使用场景:解决特定条件下的等待问题,比如点击等交互性行为

  • 常见 expected_conditions

类型 示例方法 说明
element elementToBeClickable()
visibilityOfElementLocated() 针对于元素,比如判断元素是否可以点击,或者元素是否可见
url urlContains() 针对于url
title titleIs() 针对于标题
frame frameToBeAvailableAndSwitchToIt() 针对于frame
alert alertIsPresent() 针对于弹窗
具体可详见:ExpectedConditions说明
  • 定制等待条件

官方的 ExpectedConditions 不可能覆盖所有场景,故需要定制等待条件且定制封装条件会更加灵活、可控。

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.time.Duration;


public class ElementLocate {
    private static WebDriver driver;

    // 前置条件 driver实例化
    @BeforeAll
    static void setUP() {
        System.setProperty("webdriver.chrome.driver", "/Users/wangtao/TestTools/Java/SeleniumCase/src/main/resources/ChromeDriver/chromedriver");
        driver = new ChromeDriver();
    }

    // 后置操作 浏览器退出
    @AfterAll
    static void tearDown() {
        driver.quit();
    }

    //测试步骤
    @Test
    public void locatorByID() {
        // 打开网址
        driver.get("https://vip.ceshiren.com/#/ui_study");
        // 窗口最大化
        driver.manage().window().maximize();
        // 显示等待,等待按钮success_btn,可点击的时候操作
        WebElement resElement = new WebDriverWait(driver,
                Duration.ofSeconds(10))
                .until(ExpectedConditions.elementToBeClickable(
                        By.id("success_btn")));
        resElement.click();
    }
}
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.time.Duration;


public class TeatCase {

    public static WebDriver webDriver;

    public static WebDriverWait wait;

    // 前置条件 driver实例化
    @BeforeAll
    static void setUP() {
        System.setProperty("webdriver.chrome.driver", "/Users/wangtao/TestTools/Java/SeleniumJava/SeleniumStudyL1/src/main/resources/ChromeDriver/chromedriver");
        webDriver = new ChromeDriver();
        wait = new WebDriverWait(webDriver, Duration.ofSeconds(1000));
    }

    // 后置操作 浏览器退出
    @AfterAll
    static void tearDown() {
        webDriver.quit();
    }

    //测试步骤
    @Test
    public void elementOperate() throws InterruptedException {
        // 打开页面
        webDriver.get("https://vip.ceshiren.com/#/ui_study");
        Thread.sleep(1000);
        //显示等待,定制显示等待的条件
        wait.until((driver) -> {
            driver.findElement(By.xpath("//*[text()='点击两次响应']")).click();
            return driver.findElement(By.xpath("//*[text()='该弹框点击两次后才会弹出']"));
        });
    }
}
FluentWait等待
  • 什么是FluentWait

    • 与显式等待近似
    • 设定超时时间
    • 设定轮询频率
    • 忽略特定类型的异常
  • 使用场景

    • 更深层次的定制

      • 轮询频率
      • 忽略指定异常
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.FluentWait;
import org.openqa.selenium.support.ui.Wait;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.time.Duration;


public class TeatCase {

    public static WebDriver webDriver;

    // 前置条件 driver实例化
    @BeforeAll
    static void setUP() {
        System.setProperty("webdriver.chrome.driver", "/Users/wangtao/TestTools/Java/SeleniumJava/SeleniumStudyL1/src/main/resources/ChromeDriver/chromedriver");
        webDriver = new ChromeDriver();
    }

    // 后置操作 浏览器退出
    @AfterAll
    static void tearDown() {
        webDriver.quit();
    }

    //测试步骤
    @Test
    public void elementOperate() throws InterruptedException {
        // 打开网址
        webDriver.get("https://vip.ceshiren.com/#/ui_study");
        //FluentWait等待条件设置(超时值,轮询频率,忽略异常)
        Wait<WebDriver> wait1=new FluentWait<WebDriver>(webDriver)
                //设置等待评估条件为真的时间 ---超时值
                .withTimeout(Duration.ofSeconds(30))
                ////设置评估条件的频率 ---轮询频率
                .pollingEvery(Duration.ofSeconds(5))
                // 忽略特定类型的异常
                .ignoring(NoSuchElementException.class);
        // 设置FluentWait结束条件
        WebElement ele = wait1.until((webDriver)->
                webDriver.findElement(By.id("warning_btn")));
        ele.click();
    }
}

总结

在编写脚本的调试阶段,通常会使用强制等待来进行。一旦脚本调试完成,就可以根据元素的具体情况选择切换成隐式等待或者是显示等待。对于FluentWait等待,通常情况下使用得比较少,只有在需要进行定制的情况下才会使用。