Selenium 自动化 —— 四种等待(wait)机制

news2024/12/23 10:56:23

 更多关于Selenium的知识请访问CSND论坛“兰亭序咖啡”的专栏:专栏《Selenium 从入门到精通》


目录

目录

需要等待的场景

自己实现等待逻辑

Selenium 提供的三种等待机制

隐式等待(Implicit Waits)

隐式等待的优点

隐式等待的缺点

显式等待(Explicit Waits)

显式等待的优点

显式等待的缺点

自定义等待(Custom Waits)

自定义等待的优点

自定义等待的缺点

总结


需要等待的场景

在 UI 自动化时,我们通常需要等待,比如以下场景:

  •  登录后,页面会跳转,我们需要等待页面完全加载(否则,没ready访问元素会找不到
  • 点击搜索按钮后,页面异步刷新,我们需要等待加载框消失(否则,结果还没有update,拿到错误的数据
  • 页面满足部分条件后,预定按钮才会可以点击,我们需要等待它变成激活状态(否则,按钮还是disabled的状态,出现点击报错
  • ……

总之,这些等待,对于我们测试的稳定性和正确性非常重要。

自己实现等待逻辑

最简单的方法是,我们自己写一个While循环不断地检查条件是否满足。

while(true){
   if(checkCondition()){
      doSomeThing();
   }else{
      Thread.sleep(n秒);
   }
}

不过这么做不但麻烦,自己实现也容易出错。值得庆幸的是,Selenium 就提供了内置的机制,帮助我们实现等待的功能。

学习中可以造轮子,帮助我们理解原理,但是生产项目中尽量用成熟的轮子。

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 主要分为:

  1. 显式等待(Explicit Waits)
  2. 隐式等待(Implicit Waits)
  3. 自定义等待(Custom Waits)

 下面我们分别介绍它们。

隐式等待(Implicit Waits)

隐式等待是全局设置,设置一次后,对整个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();
}

如果很多地方都这样检查,那么花费的时间会很长很长!

显式等待(Explicit Waits)

上面说过,隐式等待是全局一致的,如果我们想更灵活的等待,对一些元素希望等待时间可以短一些,对另一些希望能够多等一些时间,这时显式等待就派上用场了。

@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. 对不同的元素设置不同的等待条件

显式等待的缺点

更复杂,维护起来也麻烦。

如果不是很熟悉,乱使用,容易适得其反。

自定义等待(Custom Waits)

显式等待看上去很强大了,是不是就很完美了呢?

特殊场景下,如果你又更苛刻的要求,你也可以定制化自己的等待,进一步的更精细的控制等待,比如:

  •  自定义重试检查的周期
  • 找不到抛异常时,想根据Exception做一些处理(因为隐式、显式等待超时后都是直接抛出Timeout异常的,默认不做处理往外抛)
  • 定制超时后的异常消息文本
    @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种等待机制(包括默认的),有了这些等待,可以大大的提高我们测试的准确性和稳定性。这几种机制没有哪个最好,我们需要根据实际的情况选择最合适的等待。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1677334.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

山西省特岗教师报名流程及报名照片处理方法

山西省2024年特岗教师招聘公告已发布&#xff0c;计划招聘特岗教师1800名&#xff0c;这对于有志于教育事业的高校毕业生来说&#xff0c;无疑是一个极好的机会。本文将详细介绍报名流程&#xff0c;并提供报名照片处理的方法&#xff0c;帮助应聘者顺利通过报名环节。 一、报名…

USB3.0接口——(2)数据结构

1.数据结构 在 USB 3.0 及更高版本的 xHCI 协议中&#xff0c;“Rings”、“Transfer Request Block (TRB)” 和 “Transfer Descriptor (TD)” 是用于管理 USB 数据传输和事件的重要概念。 1.1.Rings Rings是指一种数据结构&#xff0c;用于组织和管理 USB 数据传输和事件。…

走进Java接口测试之多数据源切换示例

文章目录 一、前言二、demo实现2.1、开发环境2.2、构建项目2.3、配置数据源2.4、编写配置文件2.5、编写Dao层的mapper2.6、编写实体成层2.7、编写测试类2.8、验证结果 三、多数据源 demo 实现3.1、配置数据源3.2、增加pom文件3.3、修改数据源读取方式&#xff1a;3.4、增加动态…

Redis-持久化操作-AOF

持久化操作-AOF AOF是什么&#xff1f; 以日志的形式来记录每个写操作&#xff0c;将Redis执行过的所有写指令记录下来&#xff08;读操作不记录&#xff09;&#xff0c;只允许加文 件但不可以改写文件&#xff0c;redis启动之初会读取该文件重新构建数据&#xff0c;换言之…

UE5C++ FString做为参数取值时报错error:C4840

问题描述 用来取FString类型的变量时报错&#xff1a; 问题解决 点击错误位置&#xff0c;跳转到代码&#xff1a; void AMyDelegateActor::TwoParamDelegateFunc(int32 param1, FString param2) {UE_LOG(LogTemp, Warning, TEXT("Two Param1:%d Param2:%s"), param…

【案例】使用Vue实现标题项元素上下移动

效果图 效果说明 每一组数据只能在对应的二级类目中进行上下移动&#xff0c;当点击上移图标的时候【左边的】会将当前元素与上一个元素交换位置&#xff0c;当点击的元素为该组的第一个元素时&#xff0c;将提示已经是第一项了并且不能进行移动&#xff1b;当点击下移图标的时…

03-数据结构(一)

链接&#xff1a;C# 数据结构_哔哩哔哩_bilibili https://www.bilibili.com/video/BV1a541147Nk/?spm_id_from333.337.search-card.all.click&vd_source6eb7d966aa03ff5cb02b63725f651e68 链接&#xff1a;使用 C#.Net 学习掌握数据结构 (更新中)_哔哩哔哩_bilibili 一…

aws s3

列出关键点 创建s3 设置s3策略&#xff0c;所有人访问 { "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor1", "Effect": "Allow", …

【美团面试2024/05/14】前端面试题滑动窗口

一、题目描述 设有一字符串序列 s&#xff0c;确定该序列中最长的无重复字母的子序列&#xff0c;并返回其长度。 备注 0 < s.length < 5 * 104 s 由英文字母、数字、符号和空格组成 示例1 输入 s "abcabcbb" 输出 3 二、原题链接 这道题在LeetCode上的原题链…

【C语言】4.C语言数组(2)

文章目录 6. 二维数组的创建6.1 ⼆维数组的概念6.2 ⼆维数组的创建 7. 二维数组的初始化7.1 不完全初始化7.2 完全初始化7.3 按照⾏初始化7.4 初始化时省略⾏&#xff0c;但是不能省略列 8. 二维数组的使用8.1 ⼆维数组的下标8.2 ⼆维数组的输⼊和输出 9. 二维数组在内存中的存…

基于 Spring Boot 博客系统开发(九)

基于 Spring Boot 博客系统开发&#xff08;九&#xff09; 本系统是简易的个人博客系统开发&#xff0c;为了更加熟练地掌握 SprIng Boot 框架及相关技术的使用。&#x1f33f;&#x1f33f;&#x1f33f; 基于 Spring Boot 博客系统开发&#xff08;八&#xff09;&#x1f…

day15 个人博客项目登录验证CookieSession验证码安全

知识点 1.后台验证-登录用户逻辑安全 2.后台验证-cookie和session 3.后台验证-验证码和万能密码 通常的后台验证登录都是&#xff0c;1.发送登录请求&#xff0c;账户密码&#xff1b;2.接受账号密码3.对账号密码进行判断 正确 -》跳转到成功登录界面 失败-》重新登录 而…

C++ | Leetcode C++题解之第90题子集II

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<int> t;vector<vector<int>> ans;vector<vector<int>> subsetsWithDup(vector<int> &nums) {sort(nums.begin(), nums.end());int n nums.size();for (int mask …

无人机+应急通信:灾害现场应急通信车技术详解

无人机和应急通信车是灾害现场应急通信中的重要技术。无人机可以通过快速到达灾害现场&#xff0c;搭载高清摄像头、红外热成像仪、激光雷达等设备&#xff0c;对灾区进行实时监测和灾情评估&#xff0c;同时也可以通过搭载的通信设备&#xff0c;与指挥中心进行实时通信和数据…

HC-Net: 自动牙周疾病诊断的混合分类网络

文章目录 HC-Net: Hybrid Classification Network for Automatic Periodontal Disease Diagnosis摘要方法实验结果 HC-Net: Hybrid Classification Network for Automatic Periodontal Disease Diagnosis 摘要 从全景X射线图像中准确分类牙周病对于临床高效诊疗至关重要&…

胖东来5月生鲜陈列欣赏

【免责声明】&#xff1a;凡未注明来源的图文内容&#xff0c;版权归原作者所有。本平台所发稿件、图片均用于学习交流&#xff0c;不代表赞同文章观点和对其真实性负责&#xff0c;不用作商业用途。若文章涉及版权&#xff0c;请将马上联系&#xff0c;安排删除。

Andorid Input事件 注入方法及原理介绍

在Android系统中&#xff0c;除了真实的输入设备可以产生事件之外&#xff0c;我们也可以通过软件的方式&#xff0c;模拟一个输入事件&#xff0c;比如模拟一个点击事件&#xff0c;模拟一个按键事件等等。 怎么模拟一个输入事件 1&#xff0c;在adb命令行使用input命令模拟输…

Milvus的系统架构

简介 Milvus的构建在许多知名的向量搜索库比如Faiss, HNSW, DiskANN, SCANN等之上的&#xff0c;它针对稠密向量数据集的相似搜索而设计&#xff0c;能支持百万、十亿甚至万亿级别的向量搜索。 Milvus支持数据分片&#xff0c;流式数据插入&#xff0c;动态schema&#xff0c…

仿C#或Java基础类型自定义

class Int{ private:int _value 0; public:operator int() const{ // 隐式转换return _value;}// 显式转换explicit operator int*() const { return nullptr; }operator(const int page){_value page;}operator float() const{return static_cast<float>(_value);}ope…

Linux shell编程学习笔记49:strings命令

0 前言 在使用Linux的过程中&#xff0c;有时我们需要在obj文件或二进制文件中查找可打印的字符串&#xff0c;那么可以strings命令。 1. strings命令 的功能、格式和选项说明 我们可以使用命令 strings --help 来查看strings命令的帮助信息。 pupleEndurer bash ~ $ strin…