目录

Life in Flow

知不知,尚矣;不知知,病矣。
不知不知,殆矣。

X

Selenium

Web UI 自动化测试

    • 利用软件工具模拟用户在图形界面上与应用程序交互的过程,自动执行测试用例并验证 UI 的功能是否符合预期
    • 使用自动化工具来打开网站/定位页面元素、操作元素(如输入文本、点击按钮等)模拟用户行为(如下拉菜单、滑动页面等)
    • 通过 UI 自动化测试可以 提高测试效率、确保回归测试的全面性,减少重复工作,且对持续集成和持续部署过程帮助很大
    • UI 自动化技术也可以爬取网页的核心内容,并且结合数据处理,存储到数据库和二次使用,即爬虫应用

1719190986445.jpg

  • 优点:
    • 高效率
      • 可以在较短时间内执行大量的测试用例,提高测试效率,对于回归测试,可以显著减少测试所需的时间和人力。
    • 减少人为错误
      • 自动化测试脚本是由代码控制的,相比于人工测试,可以减少由于人为因素导致的错误。
    • 可重复性和一致性
      • 自动化测试脚本可以反复执行,每次测试的条件和步骤都是一致的,保证测试的一致性和可重复性。
    • 更好的资源利用
      • 自动化测试可以在非工作时间执行,如夜间,充分利用无人值守时间,提高了资源的利用率。
  • 缺点:
    • 不能完全取代手工测试
      • 自动化测试虽然可以执行大量的测试用例,但对于一些需要人脑判断结果的测试用例
      • 或者对于新功能的首次测试,仍然需要手工测试。
    • 测试脚本的维护成本高
      • 当被测系统的 UI 或功能发生变化时,自动化测试脚本也需要进行修改,会增加测试的工作量。
    • 测试质量依赖性强
      • 自动化测试的效果在很大程度上取决于测试脚本的质量。
      • 如果测试脚本设计得不合理或者存在缺陷,那么自动化测试的结果可能也会存在问题。
    • 技术门槛高
      • 自动化测试需要测试人员具备一定的编程能力,能够编写和维护测试脚本
      • 这对于一些非技术背景的测试人员来说,可能会有一定的难度。
  • 适用场景
    • 需求稳定的项目​:当软件需求相对稳定,不经常发生变动时,自动化测试可以更加有效地实施。
    • UI 界面变动少​:如果用户界面(UI)设计稳定,不会频繁更改,自动化测试脚本的维护成本会降低,使得自动化测试更加可行。
    • 项目周期长​:对于长期项目,自动化测试可以在项目的整个生命周期中持续提供价值,通过不断的回归测试来确保软件质量。
    • 大量的回归测试​:在需要进行大量回归测试的情况下,自动化测试可以大幅度提高效率和准确性。

1719191016651.jpg

  • 不适用的场景​:
    • 需求频繁变更的项目​:如果项目的需求经常变动,那么自动化测试脚本也需要不断地更新,这会增加维护成本。
    • 初创期的产品​:对于处于初创阶段的产品,由于功能和界面可能会有很大的变动,自动化测试可能不是最佳选择。
    • 一次性或短期项目​:对于只需要运行一次或短期的测试项目,建立自动化测试可能不值得,因为其回报周期较长。

Web UI 自动化技术解决方案选择

    • Selenium
      • 是一个广泛使用的 Web UI 自动化测试工具 ,适合进行大规模的回归测试、跨浏览器和跨平台的测试

      • 支持多种浏览器(如 Chrome、Firefox、Safari 等)和操作系统(如 Windows、Linux、macOS 等)

      • 优点​:

        • 支持多种浏览器和操作系统。
        • 丰富的 API,可以灵活地操作页面元素。
        • 社区活跃,有大量的教程和资料可供参考。

        缺点​:

        • 学习曲线较陡峭,需要一定的编程基础。
        • 对于某些复杂的 UI 交互,可能需要编写较复杂的脚本。
        • 在某些情况下,可能无法稳定地识别页面元素。
    • Puppeteer
      • 是 Google 开发的一个 Node 库,它提供了一个高级 API 来通过 DevTools 协议控制 Chrome 或 Chromium。
      • 适合进行 Chrome 浏览器的自动化测试和操作。
      • 优点​:
        • 基于 Chrome 浏览器,兼容性好。
        • 提供了丰富的 API,可以方便地操作页面元素和模拟用户行为。
        • 支持无头模式,可以在没有浏览器界面的情况下运行。
      • 缺点​:
        • 只支持 Chrome 浏览器。
        • 对于一些复杂的 UI 交互,可能需要编写较复杂的脚本
  • 回答思路
    • 对内:技术框架满足业务需求,团队多数人员熟悉相关产品
    • 对外:模拟真实用户的交互行为,功能强大,支持多种浏览器和操作系统,社区活跃。
    • 结论
      • 在选择 Web UI 自动化技术解决方案时,需要根据具体的测试需求、项目规模、团队技能等因素进行综合考虑
      • 也可以考虑将不同的技术结合起来,以充分发挥它们的优势

Selenium 自动化测试框架介绍和原理

  • Selenium 自动化测试框架

    • 是一个用于 Web 应用程序测试的自动化测试工具
    • 支持多种浏览器(如 Chrome、Firefox、Safari 等)和操作系统(如 Windows、Linux、macOS 等),
    • 提供了一个丰富的 API,允许用户模拟真实用户的交互行为,如点击、输入、提交等
    • 官网:https://www.selenium.dev
    • 特点
      • 跨平台与多浏览器支持​:Selenium 可以在不同的操作系统和浏览器上运行,提供了广泛的兼容性。
      • 开源与免费​:Selenium 是一个开源项目,用户可以免费地使用其中的工具和库。
      • 强大的 API​:Selenium 提供了丰富的 API,允许用户进行复杂的页面操作和验证。
      • 支持自动化测试​:Selenium 可以模拟真实用户的交互行为,从而进行自动化测试,提高测试效率。
      • 集成与扩展性​:可以与其他测试工具(如 Jenkins)和编程语言(如 Python、Java 等)集成,提供了很好的扩展性。
    • 优点​:
      1. 灵活性​:Selenium 提供了丰富的 API,用户可以根据自己的需求进行定制化的测试。
      2. 开源与免费​:Selenium 是一个开源项目,用户可以免费地使用其中的工具和库,降低了测试成本。
      3. 跨平台与多浏览器支持​:Selenium 可以在不同的操作系统和浏览器上运行,提供了广泛的兼容性。
    • 缺点​:
      1. 学习曲线陡峭​:对于初学者来说,Selenium 的学习成本可能较高,需要掌握一定的编程和测试知识。
      2. 性能问题​:由于 Selenium 模拟真实用户的交互行为,所以相比于传统的性能测试工具,其执行速度可能较慢。
      3. 对页面结构敏感​:Selenium 的脚本编写通常依赖于页面的 DOM 结构,如果页面结构发生变化,需要相应地更新测试脚本
  • Selenium 框架的原理

    • 通过 WebDriver 与浏览器进行交互,WebDriver 是一个 API 和协议,定义了用于控制 Web 浏览器行为的接口。
    • Selenium 通过调用 WebDriver 接口方法完成对浏览器的操作,如点击、输入、提交等。
    • 这些操作都通过 HTTP 请求发送给浏览器驱动,浏览器驱动再转发给浏览器执行。

    1719192227903.jpg

  • Selenium 框架的使用步骤

    • 环境搭建​(最多人踩坑的地方-​浏览器版本和驱动版本对应关系​)
      • 安装 Selenium 库,不同语言采用不同依赖包安装
      • 下载与浏览器对应的 WebDriver,如 ChromeDriver 或 GeckoDriver,并确保它们与浏览器版本匹配。
      • 【强调三遍!!!!】浏览器版本一定要和驱动版本一一对应,不然存在不兼容问题
    • 编写测试脚本
      • 使用 Selenium 提供的 API 编写测试脚本
      • 通常包括启动 WebDriver、打开浏览器、执行用户请求(如点击按钮、填写表单等)、获取页面元素等操作。
    • 运行测试脚本
      • 将脚本文件与 WebDriver 和浏览器一起运行,以执行自动化测试。
    • 分析结果
      • 根据测试结果分析潜在的问题和缺陷,并进行相应的修复和优化

Win11 系统 +Selenium4.X+Chrome 环境安装

  • 前置环境说明

    • 课程采用 ​JDK21 版本 +Maven3.9 +IDEA 旗舰版​,这个是前置环境需要自己安装
    • 参考博文资料,相关 JDK 和 Maven 安装包课程资料里面有提供
    • 如果遇到问题可以在,我们小滴课堂技术群里发,技术讲师会协助你解决
  • 环境说明

    • 课程演示环境版本:Win11 系统 +JDK21+Maven3.9+Selenimum4.X
    • 注意:如果安装失败,可以搜索下博文参考,每个人系统和浏览器版本不一样,有 win8,win10,win11,根据关键词搜索即可
  • 驱动相关注意事项(如果驱动版本太新,可以降低版本验证)

    • 浏览器版本

1719400421875.jpg

image.png

路径

1C:\Tools\chrome-win64

chromedriverwin64.zip

创建 Java 项目,测试驱动环境
增加依赖

1<dependencies>
2        <!-- Selenium -->
3        <dependency>
4            <groupId>org.seleniumhq.selenium</groupId>
5            <artifactId>selenium-java</artifactId>
6            <version>4.10.0</version>
7        </dependency>
8   </dependencies>

控制代码

 1package com.soulboy;
 2
 3import org.openqa.selenium.WebDriver;
 4import org.openqa.selenium.chrome.ChromeDriver;
 5import org.openqa.selenium.chrome.ChromeOptions;
 6
 7public class Main {
 8    public static void main(String[] args) {
 9        //指定驱动路径
10        System.setProperty("webdriver.chrome.driver","C:\\Tools\\chromedriver-win64\\chromedriver.exe");
11        // 谷歌驱动
12        ChromeOptions options = new ChromeOptions();
13        // 允许所有请求
14        options.addArguments("--remote-allow-origins=*");
15        WebDriver webDriver = new ChromeDriver(options);
16        // 启动需要打开的网页
17        webDriver.get("https://abc1024.tech");
18    }
19}

自动化测试 Chrome 调试工具和 Selenium4.X 定位

调试工具和基础知识说明

  • 不管是爬虫还是 Web 的 UI 自动化测试,需要查找和识别 UI 元素.
  • 所以需要了解 HTML, CSS 和 JavaScript 的一些知识, 还需要学会使用各种浏览器的调试功能
  • 谷歌浏览器页面调试工具
    1719404473635.jpg
  • 拷贝对应的元素的 xpath 路径
    1719404504463.jpg
  • 其他工具:Firefox 的 firebug 插件
  • 自动化测试步骤
    image.png
    Selenium 常见的元素定位方式概述
  • 比较常用的是 id 选择器和 xpath 选择器
定位方法 Java 语言实现实例
id 定位 driver.findElement(By.id(“id 的值”));
name 定位 driver.findElement(By.name(“name 的值”));
链接的全部文字定位 driver.findElement(By.linkText(“链接里面的的全部文字”));
链接的部分文字定位 driver.findElement(By.partialLinkText(“链接里面的部分文字”));
CSS 方式定位 driver.findElement(By.cssSelector(“CSS 表达式”));
xpath 方式定位 driver.findElement(By.xpath(“xpath 表达式”));
Class 名称定位 driver.findElement(By.className(“class 属性”));
TagName 标签名称定位 driver.findElement(By.tagName(“标签名称”));

Selenium4.X 元素定位之 ID

  • 元素定位方法说明
    • 在使用 webdriver 进行元素定位时,通常用 findElementfindElements 方法结合 By 类返回元素句柄来定位元素
    • findElement() 方法返回一个元素, 如果没有找到,会抛出一个异常 NoElementFindException()
    • findElements()方法返回多个元素, 如果没有找到,会返回空数组, 不会抛出异常
  • Selenium4 元素定位之 ID 方式
    • ID 元素定位
      • HTML 中的每个元素都可以设置一个唯一的 ID 属性。通过该属性 可以精确地定位到页面上的某个元素。
      • 在 Selenium 中,使用 findElement(By.id(“id的值”)); 方法可以根据元素的 ID 进行定位。
    • 注意事项​:
      • ID 应该是唯一的,因此在页面上不应该有两个或更多的元素具有相同的 ID。
      • 如果元素的 ID 发生了改变,或者页面上没有该 ID 的元素,那么定位会失败。
 1package com.soulboy;
 2
 3import org.openqa.selenium.By;
 4import org.openqa.selenium.WebDriver;
 5import org.openqa.selenium.chrome.ChromeDriver;
 6import org.openqa.selenium.chrome.ChromeOptions;
 7
 8import java.util.concurrent.TimeUnit;
 9
10public class Main {
11    public static void main(String[] args) throws InterruptedException {
12        //指定驱动路径
13        System.setProperty("webdriver.chrome.driver","C:\\Tools\\chromedriver-win64\\chromedriver.exe");
14        // 谷歌驱动
15        ChromeOptions options = new ChromeOptions();
16        // 允许所有请求
17        options.addArguments("--remote-allow-origins=*");
18        WebDriver webDriver = new ChromeDriver(options);
19        // 最大化浏览器
20        webDriver.manage().window().maximize();
21
22        //运行测试用例
23        idTest(webDriver);
24    }
25
26    public static void idTest(WebDriver webDriver) throws InterruptedException {
27        webDriver.get("https://xdclass.net");
28        TimeUnit.SECONDS.sleep(4);
29        // 利用id定位元素:输入框,并在输入框中输入:设计模式
30        //sendKeys在对象上模拟按键输入内容
31        webDriver.findElement(By.id("rc_select_0")).sendKeys("设计模式");
32    }
33
34}

Selenium4.X 元素定位 Name

  • Name 元素定位
    • 在 HTML 中,某些元素(如 <input>, <button>, <select> 等)可以设置一个 Name 属性。
    • 虽然 Name 属性不必唯一,但在某些情况下,它可以用于定位特定的元素。
    • 在 Selenium 中,使用 findElement(By.name(“name的值”)); 方法可以根据元素的 Name 属性进行定位
  • 注意事项​:
    • Name 属性不必唯一,可能存在多个元素具有相同的 Name,默认只会返回第一个匹配的元素。
    • 如果页面上的元素没有设置 Name 属性,或者 Name 属性的值发生了改变,那么定位会失败
  • 案例实操
 1package com.soulboy;
 2
 3import org.openqa.selenium.By;
 4import org.openqa.selenium.WebDriver;
 5import org.openqa.selenium.chrome.ChromeDriver;
 6import org.openqa.selenium.chrome.ChromeOptions;
 7
 8import java.util.concurrent.TimeUnit;
 9
10public class Main {
11    public static void main(String[] args) throws InterruptedException {
12        //指定驱动路径
13        System.setProperty("webdriver.chrome.driver","C:\\Tools\\chromedriver-win64\\chromedriver.exe");
14        // 谷歌驱动
15        ChromeOptions options = new ChromeOptions();
16        // 允许所有请求
17        options.addArguments("--remote-allow-origins=*");
18        WebDriver webDriver = new ChromeDriver(options);
19        // 最大化浏览器
20        webDriver.manage().window().maximize();
21
22        //运行测试用例
23        nameTest(webDriver);
24    }
25    public static void nameTest(WebDriver webDriver){
26        webDriver.get("https://www.baidu.com");
27        webDriver.findElement(By.name("wd")).sendKeys("周杰伦");
28    }
29}

Selenium4.X 元素定位之 linkText 链接

Selenium4 元素定位之链接方式

  • 通过超链接上的文字信息来定位元素,包括通过链接的全部文字和部分文字进行定位。
  • 链接的全部文字定位
    • 当链接的完整文本是唯一的,想要定位这个链接时,可以使用 By.linkText 方法
    • By.linkText("完整的链接文本") 用于查找页面上文字完全匹配的链接。
    • 案例操作
 1public static void linkTest(WebDriver webDriver) throws InterruptedException {
 2        webDriver.get("https://xdclass.net");
 3        TimeUnit.SECONDS.sleep(2);
 4        //关闭广告
 5        webDriver.findElement(By.xpath("/html/body/div/div/div[2]/div/div/a/div/div/button/span")).click();
 6        TimeUnit.SECONDS.sleep(1);
 7
 8        WebElement webElement = webDriver.findElement(By.linkText("课程中心"));
 9        String text = webElement.getText();
10        System.out.println(text);
11        //点击元素
12        webElement.click();
13    }

链接的部分文字定位

  • 当链接的文本不是唯一的,想基于部分文本来定位链接时,可以使用 By.partialLinkText 方法。
  • By.partialLinkText("部分链接文本") 用于查找页面上文字包含指定文本的链接。
  • 案例操作
 1public static void partialLinkTest(WebDriver webDriver) throws InterruptedException {
 2        webDriver.get("https://xdclass.net");
 3        TimeUnit.SECONDS.sleep(3);
 4        //关闭广告
 5        webDriver.findElement(By.xpath("/html/body/div/div/div[2]/div/div/a/div/div/button/span")).click();
 6        TimeUnit.SECONDS.sleep(1);
 7
 8        List<WebElement> webElements = webDriver.findElements(By.partialLinkText("课程"));
 9        System.out.println(webElements.size());
10
11        WebElement firstElement = webElements.getFirst();
12        System.out.println(firstElement);
13        //点击元素
14        firstElement.click();
15    }
  • 注意事项

    • 确保链接的文本或部分文本是唯一的,否则可能会定位到错误的元素。
    • 当页面包含多个符合条件元素时
      • findElement 方法只会返回第一个查找到的元素,而不会返回所有符合条件的元素
      • 如果想要获得所有符合条件的元素,还是只能用 findElements 方法
    • 链接的文本是区分大小写的,确保在定位时使用了正确的大小写。
    • 如果页面上的链接动态变化或者链接的文本是通过 JS 生成的,需要使用其他定位策略或等待机制
    • 如显式等待或隐式等待来确保元素正确加载后再进行定位。

    Selenium4.X 元素定位之 Class

Selenium4 元素定位之 Class 方式

  • 通过元素属性 class 定位元素,查找一个或一组显示效果相同的页面元素 driver.findElement(By.className(“class属性”));

HTML 代码

1<a class="reg" href="https://api.xdclass.net/api/regisgter">注册</a>

语法代码

1WebElement element = driver.findElement(By.className( "reg"));

代码实战

 1public static void classTest(WebDriver webDriver) throws InterruptedException {
 2        webDriver.get("https://xdclass.net");
 3        TimeUnit.SECONDS.sleep(2);
 4        //关闭广告
 5        webDriver.findElement(By.xpath("/html/body/div/div/div[2]/div/div/a/div/div/button/span")).click();
 6        //获取class为card-box的元素
 7        List<WebElement> elements = webDriver.findElements(By.className("card-box"));
 8        System.out.println("size======="+elements.size());
 9        for (WebElement element : elements) {
10            //获取该元素下的文本内容
11            String text = element.getText();
12            System.out.println(text);
13        }
14    }

输出

 1size=======26
 2会员特惠
 3手撕大厂算法-算法刷题大课训练营
 4级别:高级
 512897
 6¥3199
 7¥2599
 8会员特惠
 9中间件项目大课-自动化云测平台/Spingboot3.X/微服务/Kafka3.x
10级别:高级
1113583
12¥5799
13¥5299
14会员特惠
15全栈多端低代码平台项目大课-系统化掌握React生态体系
16级别:高级
1712653
18¥3599
19¥2899
20会员特惠
21独孤求败-小滴云架构大课十八式-最强面试大课
22级别:高级
2331241
24¥8999
25¥7299

Selenium4.X 元素定位之 CSS

  • Selenium4 元素定位之 CSS 选择器方式

    • selenium 中的 CSS 定位,是通过 CSS 选择器来定位到具体元素,CSS 选择器来自于 CSS 语法
    • CSS 相较与 xpath 选择元素:表达式更加简洁,一般情况 CSS 的运行速度是优于 xpath 的。
    • 常见的选择器包括:
      • 标签:直接使用标签名,如下列:p
      • 类(class):“.”(英文句号)+class 值
      • id:“#”+id 值*
      • 通配符:意为匹配所有元素, 用“*”表示
    • 整理以下表格方便记忆
    基础选择器 作用 例如
    元素标签 直接使用 HTML 标签 driver.findElement(By.cssSelector("div"));
    类选择器 使用点符号加类名 driver.findElement(By.cssSelector(".className"));`
    ID 选择器 使用井号加 ID 名称 driver.findElement(By.cssSelector("#idName"));
  • 常见的 CSS 选择器说明

    • 元素选择器(Element Selector)
      • 选择特定类型的 HTML 元素。
      • 示例:pdivinput[type="text"]
      • 可以使用如 By.cssSelector('p') 来查找第一个 <p> 元素。
    • 类选择器(Class Selector)
      • 选择具有特定类名的元素。
      • 示例:.classname
      • 在 UI 自动化中,(By.cssSelector'.classname') 会查找具有指定类名的元素。
    • ID 选择器(ID Selector)
      • 选择具有特定 ID 的元素。
      • 示例:#idname
      • ID 是唯一的,所以 By.cssSelector('#idname') 通常用于唯一标识和定位元素。
    • 属性选择器(Attribute Selector)
      • 选择具有特定属性的元素。
      • 示例:[attribute=value]
      • 例如,By.cssSelector('[name="username"]') 会查找 name 属性值为 username 的元素。
    • 伪类选择器(Pseudo-class Selector)
      • 选择处于特定状态的元素,如:hover、:active、:first-child 等。
      • 注意:在 UI 自动化测试中,由于伪类通常与用户的实时交互有关,直接使用伪类选择器不太常见
    • 组合选择器(Combinator Selector)
      • 通过组合其他选择器来选择元素,使用组合选择器来更精确地定位元素。
      • 示例:div > p(选择所有 <div> 元素的直接 <p> 子元素)。
    • 后代选择器(Descendant Selector)
      • 选择指定元素的后代元素。
      • 示例:div p(选择所有 <div> 元素内的 <p> 元素)。
    • 相邻兄弟选择器(Adjacent Sibling Selector)
      • 选择紧跟在另一个元素后的元素,且二者有相同的父元素。
      • 示例:div + p(选择紧接在 <div> 元素后的 <p> 元素)。
    • 通用兄弟选择器(General Sibling Selector)
      • 选择指定元素之后的所有兄弟元素,且二者有相同的父元素。
      • 示例:div ~ p(选择 <div> 元素之后的所有 <p> 兄弟元素)。
  • 使用 CSS 选择器定位元素案例说明

1// 通过类名定位  
2WebElement elementByClassName = driver.findElement(By.cssSelector(".class-name"));  
3// 通过ID定位(虽然通常使用By.id更直接)  
4WebElement elementById = driver.findElement(By.cssSelector("#element-id"));  
5// 通过标签名定位  
6WebElement elementByTagName = driver.findElement(By.cssSelector("div"));  
7// 通过属性定位  
8WebElement elementByAttribute = driver.findElement(By.cssSelector("input[name='input-name']"));

测试代码

 1public static void cssTest(WebDriver webDriver) throws InterruptedException {
 2        webDriver.get("https://xdclass.net");
 3        TimeUnit.SECONDS.sleep(3);
 4        //关闭广告
 5        webDriver.findElement(By.xpath("/html/body/div/div/div[2]/div/div/a/div/div/button/span")).click();
 6        TimeUnit.SECONDS.sleep(1);
 7
 8        List<WebElement> elements = webDriver.findElements(By.cssSelector("div[class='title']"));
 9        System.out.println("size======="+elements.size());
10        for (WebElement element : elements) {
11            String text = element.getText();
12            System.out.println(text);
13        }
14    }

输出

 1size=======22
 2手撕大厂算法-算法刷题大课训练营
 3中间件项目大课-自动化云测平台/Spingboot3.X/微服务/Kafka3.x
 4全栈多端低代码平台项目大课-系统化掌握React生态体系
 5独孤求败-小滴云架构大课十八式-最强面试大课
 6全栈-商业级大型前端项目大课-小滴云在线教育平台
 7微服务架构-海量数据商用短链平台项目大课【完结】
 83天掌握 WebUI 自动化测试 Selenium4.X+TestNG
 924年0基础Java-10天从入门到高手教程JDK21 + IDEA 旗舰版
1024年全新微信小程序云开发-从0开发知乎云全栈小程序
11新版Vue3.4+ElementPlus全家桶开发视频项目实战
12新一代Node框架NestJS入门到项目实战-低代码大课必备技术
13中间件项目大课-自动化云测平台/Spingboot3.X/微服务/Kafka3.x

Selenium4.X 元素定位之 TagName

  • 标签名定位方式主要用于匹配多个页面元素的情况,将找到的页面元素对象进行计数、遍历

  • HTML 的本质就是通过 tag 来定义实现不同的功能,每一个元素本质上也是一个 tag。

  • 通过方法 driver.findElement(By.tagName(“标签名称”)); 进行操作

  • 注意事项

    • tag 往往用来定义一类功能和布局,通过 tag 识别某个元素的概率很低。
    • 如页面存在大量的 < div >,< input >,< a > 等 tag

HTML 源码

1<a name="search" href="http://www.baidu.com/setting/preferences.html">搜索设置</a>
2<a href="http://www.baidu.com">baidu搜索</a>

Java 代码

1WebElement element=driver.findElement(By.tagName("a"));
2List<WebElement> elements= driver.findElements(By.tagName(a));

测试代码

 1public static void tagNameTest(WebDriver webDriver) throws InterruptedException {
 2        webDriver.get("https://baidu.com");
 3        TimeUnit.SECONDS.sleep(2);
 4        List<WebElement> elements = webDriver.findElements(By.tagName("a"));
 5        System.out.println("size = " + elements.size());
 6        for (WebElement element : elements) {
 7            String text = element.getText();
 8            String href = element.getAttribute("href");
 9            System.out.println(text + "-----" + href);
10        }
11    }

输出结果

 1size = 63
 2-----javascript:void(0)
 3-----https://www.baidu.com/
 4-----javascript:;
 5-----https://passport.baidu.com/v2/?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2F&sms=5
 6新闻-----http://news.baidu.com/
 7hao123-----https://www.hao123.com/?src=from_pc
 8地图-----http://map.baidu.com/
 9贴吧-----http://tieba.baidu.com/
10视频-----https://haokan.baidu.com/?sfrom=baidu-top
11图片-----http://image.baidu.com/
12网盘-----https://pan.baidu.com/?from=1026962h
13文库-----https://wenku.baidu.com/?fr=bdpcindex
14更多-----http://www.baidu.com/more/
15-----http://fanyi.baidu.com/
16-----http://xueshu.baidu.com/
17-----https://baike.baidu.com/
18-----https://zhidao.baidu.com/
19-----https://jiankang.baidu.com/widescreen/home
20-----http://e.baidu.com/ebaidu/home?refer=887
21-----https://live.baidu.com/
22-----http://music.taihe.com/
23-----https://cp.baidu.com/?sa=bdindex
24-----http://www.baidu.com/more/
25登录-----https://passport.baidu.com/v2/?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2F&sms=5

Selenium4.X 元素定位之 XPath 操

  • 什么是 XPath

    • XPath(XML Path Language)是一种在 XML 文档中查找信息的语言,也可以用于 HTML
    • XPath 提供了非常强大的定位能力,可以定位到几乎任何元素。
    • 语法案例(更多语法搜索博文资料 https://www.w3school.com.cn/xpath/index.asp
    表达式 描述 实例 案例说明
    nodename 选取 nodename 节点的所有子节点 xpath(‘//div’) 选取了 div 节点的所有子节点
    / 从根节点选取 xpath(‘/div’) 从根节点上选取 div 节点
    // 选取所有的当前节点,不考虑他们的位置 xpath(‘//div’) 选取所有的 div 节点
    . 选取当前节点 xpath(‘./div’) 选取当前节点下的 div 节点
    .. 选取当前节点的父节点 xpath(‘..’) 回到上一个节点
    @ 选取属性 xpath(’//@class’) 选取所有的 class 属性
  • Selenium4 元素定位之 XPath 方式

    • HTML 文档本身就是一个标准的 XML 页面,可以使用 Xpath 的用法来定位页面元素
    • 有两种路径定位方式
      • 绝对路径
        • 以 "/" 开头, 让 xpath 从文档的根节点开始解析
        • 如果页面结构发生改变,改路径也随之失效,必须重新配置
      • 相对路径
        • 以"//" 开头, 让 xpath 从文档的任何元素节点开始解析
        • 推荐采用这个方式,结合适合的元素,则通用性更好
    • 注意事项
      • webdriver 会将整个页面的元素扫描定位所需要的元素,如果大量使用 xpath 做元素定位的话, 脚本的执行速度可能会稍慢
        *

测试代码

 1public static void xpathTest(WebDriver webDriver) throws InterruptedException {
 2        webDriver.get("https://xdclass.net");
 3        TimeUnit.SECONDS.sleep(2);
 4        //关闭广告
 5        webDriver.findElement(By.xpath("/html/body/div/div/div[2]/div/div/a/div/div/button/span")).click();
 6        //  //*[@class="title"]  *代表元素
 7        List<WebElement> elements = webDriver.findElements(By.xpath("//*[@class=\"title\"]"));
 8        System.out.println("size======="+elements.size());
 9        for (WebElement element : elements) {
10            String text = element.getText();
11            System.out.println(text);
12        }
13    }

输出结果

 1size=======26
 2手撕大厂算法-算法刷题大课训练营
 3中间件项目大课-自动化云测平台/Spingboot3.X/微服务/Kafka3.x
 4全栈多端低代码平台项目大课-系统化掌握React生态体系
 5独孤求败-小滴云架构大课十八式-最强面试大课
 6全栈-商业级大型前端项目大课-小滴云在线教育平台
 7微服务架构-海量数据商用短链平台项目大课【完结】
 83天掌握 WebUI 自动化测试 Selenium4.X+TestNG
 924年0基础Java-10天从入门到高手教程JDK21 + IDEA 旗舰版
1024年全新微信小程序云开发-从0开发知乎云全栈小程序
11新版Vue3.4+ElementPlus全家桶开发视频项目实战
12新一代Node框架NestJS入门到项目实战-低代码大课必备技术

Java 版本 Selenium4.X WebDriver

  • 什么是 WebDriver

    • Selenium WebDriver 是一个浏览器自动化框架,允许执行 Web 应用程序上的操作,就如同一个真实用户一样。
    • 在 Selenium 4.x 版本中,WebDriver API 提供了一系列与浏览器进行交互的方法,常见 API 如下
    方法 描述
    get(String url) 访问目标 url 地址,打开网页
    getCurrentUrl() 获取当前页面 url 地址
    getTitle() 获取页面标题
    getPageSource() 获取页面源代码
    close() 关闭浏览器当前打开的窗口
    quit() 关闭浏览器所有的窗口
    findElement(by) 查找单个元素
    findElements(by) 查到元素列表,返回一个集合
    getWindowHandle() 获取当前窗口句柄
    getWindowHandles() 获取所有窗口的句柄
  • 面试题: quit 和 close 的区别

    • quit 关闭了整个浏览器,close 只是关闭了当前的页面;
    • quit 会清空缓存,close 则不会;

测试代码

 1public static void WebDriver(WebDriver webDriver) throws InterruptedException {
 2        //访问目标 url 地址,打开网页
 3        webDriver.get("https://www.baidu.com/");
 4        //getCurrentUrl() 方法获取当前页面的 url 地址
 5        String currentUrl = webDriver.getCurrentUrl();
 6        System.out.println("当前页面的 url 地址是:" + currentUrl);
 7
 8        //getTitle() 方法获取当前页面的标题
 9        String title = webDriver.getTitle();
10        System.out.println("当前页面的标题是:" + title);
11
12        //getPageSource() 方法获取当前页面的源码
13        String pageSource = webDriver.getPageSource();
14        System.out.println("当前页面的源码是:" + pageSource);
15
16        //close() 方法关闭当前页面
17        //webDriver.close();
18
19        //quit() 方法关闭所有浏览器
20        //webDriver.quit();
21
22        //通过 id 定位元素,并输入搜索关键词
23        webDriver.findElement(By.id("kw")).sendKeys("小滴课堂");
24
25        //findElements() 方法返回所有匹配的元素
26        webDriver.findElements(By.id("kw")).get(0).sendKeys("小滴课堂");
27
28        String windowHandle = webDriver.getWindowHandle();
29        System.out.println("当前窗口句柄是:" + windowHandle);
30/*        Set<String> windowHandles = webDriver.getWindowHandles();
31        for (String windowHandle : windowHandles) {
32            System.out.println("当前窗口句柄是:" + windowHandle);
33        }*/
34    }

WebElement 对象 API 操作

  • 什么是 WebElement 对象

    • WebElement 是 Selenium WebDriver API 中的一个核心接口,
    • 代表了 DOM(Document Object Model)树中的一个 HTML 元素。
    • 通过 WebElement 对象,可以与页面上的元素进行交互,例如点击按钮、输入文本、选择选项、检查元素的属性或状态等。
    • 通常会通过 WebDriver 的 find_element_by_*find_elements_by_* 方法来定位页面上的元素,获取 WebElement 对象。
    • 这些方法会返回一个或多个 WebElement 对象,对象代表了与给定选择器匹配的 DOM 元素。
  • 元素对象 API 操作语法

    • WebElement 对象常用 API
    方法 说明
    click 点击对象
    sendKeys 在对象上模拟按键输入
    clear 清除对象输入的文本内容
    submit 提交,比如表单对象
    getAttribute 获取元素的指定属性
    getText 用于获取元素的文本信息
    • 备注
      • submit 用于对信息进行提交,也可以使用 click 进行代替
      • submit 要求提交对象是一个表单,click 更强调事件的独立性

测试代码

 1public static void webElementTest(WebDriver webDriver)throws InterruptedException {
 2        //启动需要打开的网页
 3        webDriver.get("https://www.baidu.com");
 4        String title = webDriver.getTitle();
 5        String currentUrl = webDriver.getCurrentUrl();
 6        System.out.println("title="+title+",currentUrl="+currentUrl);
 7
 8        TimeUnit.SECONDS.sleep(2);
 9
10        //输入元素 sendKey
11        webDriver.findElement(By.id("kw")).sendKeys("小滴课堂官网");
12        TimeUnit.SECONDS.sleep(2);
13
14        //清除元素  clear
15        webDriver.findElement(By.id("kw")).clear();
16
17        TimeUnit.SECONDS.sleep(2);
18        webDriver.findElement(By.id("kw")).sendKeys("苹果手机");
19
20        //点击元素  click
21        webDriver.findElement(By.id("su")).click();
22        TimeUnit.SECONDS.sleep(2);
23
24        webDriver.findElement(By.id("kw")).clear();
25        webDriver.findElement(By.id("kw")).sendKeys("苹果手机最新款");
26
27        //提交元素  submit
28        webDriver.findElement(By.id("su")).submit();
29        String attributeValue = webDriver.findElement(By.id("su")).getAttribute("value");
30        String attributeType = webDriver.findElement(By.id("su")).getAttribute("type");
31
32        System.out.println("attributeValue======"+attributeValue);
33        System.out.println("attributeType======"+attributeType);
34    }

image.png

输出

1title=百度一下,你就知道,currentUrl=https://www.baidu.com/
2attributeValue======百度一下
3attributeType======submit

自动化操作里面的浏览器 API 案例实战

  • 需求

    • 浏览器操作网页,有前进、后退,不同网页直接切换,窗口最大化、刷新等
    • 通过 Selenium 的 API 完成上述的操作案例
  • 浏览器案例

    • API 语法
    方法 说明
    back 模拟浏览器后退按钮
    forward 模拟浏览器前进按钮
    refresh 刷新页面(F5)
    maximize 浏览器最大化
    setSize 浏览器宽高
    manage( ).window( ).setSize( ) 设置浏览器的大小

代码分析

 1public static void browserTest(WebDriver webDriver)throws InterruptedException {
 2        //打开网页
 3        webDriver.get("https://www.baidu.com");
 4        //输入小滴课堂官网
 5        webDriver.findElement(By.id("kw")).sendKeys("小滴课堂官网");
 6        //点击搜索
 7        webDriver.findElement(By.id("su")).click();
 8        //浏览器刷新
 9        TimeUnit.SECONDS.sleep(2);
10        webDriver.navigate().refresh();
11        //浏览器后退一步
12        TimeUnit.SECONDS.sleep(2);
13        //加个休眠时间
14        webDriver.navigate().back();
15
16        //浏览器前进
17        TimeUnit.SECONDS.sleep(2);
18        webDriver.navigate().forward();
19        TimeUnit.SECONDS.sleep(2);
20
21        //浏览器窗口按照指定大小来显示
22        webDriver.manage().window().setSize(new Dimension(300,300));
23        TimeUnit.SECONDS.sleep(2);
24        //浏览器全屏
25        webDriver.manage().window().fullscreen();
26    }

WebUI 自动化操作之鼠标事件

  • Selenium 的鼠标事件

    • 鼠标操作主要是通过 Actions 类来实现的,该类提供了一系列模拟鼠标操作的方法
    • 包括有 右击、双击、悬停、拖动等
  • 鼠标案例 API 语法

    方法 说明
    contextClick( ) 右击
    clickAndHold( ) 鼠标点击并控制
    doubleClick( ) 双击
    dragAndDrop( ) 拖动
    release( ) 释放鼠标
    perform( ) 执行所有 Actions 中存储的行为
    • 单击操作
1WebElement element = driver.findElement(By.id("element_id")); // 替换为你要单击的元素的ID  
2element.click(); // 或者使用 Actions 实现单击  
3  
4// 使用 ActionChains  
5Actions actions = new Actions(driver);  
6actions.click(element).perform();
  • 双击操作
1WebElement element = driver.findElement(By.id("element_id")); // 替换为你要双击的元素的ID  
2new Actions(driver).doubleClick(element).perform();
  • 右键操作
1WebElement element = driver.findElement(By.id("element_id")); // 替换为你要右击的元素的ID  
2new Actions(driver).contextClick(element).perform();
  • 悬停操作
1WebElement element = driver.findElement(By.id("element_id")); // 替换为你要悬停的元素的ID  
2new Actions(driver).moveToElement(element).perform();
  • 拖拽操作
1WebElement sourceElement = driver.findElement(By.id("source_id")); // 源元素ID  
2WebElement targetElement = driver.findElement(By.id("target_id")); // 目标元素ID  
3new Actions(driver).dragAndDrop(sourceElement, targetElement).perform();
  • 测试代码
 1public static void mouseTest(WebDriver webDriver)throws InterruptedException{
 2        //打开网站
 3        webDriver.get("https://baidu.com");
 4
 5        webDriver.findElement(By.cssSelector("#kw")).sendKeys("iphone100");
 6
 7        //点击百度的搜索一下
 8        TimeUnit.SECONDS.sleep(2);
 9        webDriver.findElement(By.cssSelector("#su")).click();
10
11        TimeUnit.SECONDS.sleep(2);
12        WebElement element = webDriver.findElement(By.cssSelector("#s_tab > div > a.s-tab-item.s-tab-item_1CwH-.s-tab-wenku_GwhrW.s-tab-wenku"));
13
14        //鼠标右键(文库)
15        Actions actions = new Actions(webDriver);
16        actions.moveToElement(element).contextClick().perform();
17    }

WebUI 自动化里面模拟键盘输入操作

什么是模拟键盘

  • 利用 ActionsKeys 类来模拟键盘操作,包括文本输入、按键和组合键序列,增强自动化脚本的用户交互能力
  • Keys 枚举提供了方便的表示键盘上按键的方法,而 Actions 类则用于构建复杂的交互序列。
  • 这两者结合,允许在 Web 自动测试中模拟几乎任何类型的键盘操作。
  • 键盘操作示例
    • 发送普通文本
      • 可以使用 WebElementsendKeys() 方法来向页面元素发送普通文本。
      • 例如,向一个输入框发送文本“Hello, Selenium!”:
1WebElement inputBox = driver.findElement(By.id("inputBoxId"));  
2inputBox.sendKeys("Hello, Selenium!");

发送特殊字符

  • sendKeys 使用 Keys 类中的常量,可以发送特殊字符或按键事件,sendKeys 接收可变参数
1sendKeys(Keys.BACK_SPACE) 回格键(BackSpace)、sendKeys(Keys.SPACE) 空格键 (Space)
2sendKeys(Keys.TAB) 制表键 (Tab)、sendKeys(Keys.ESCAPE) 回退键(Esc)
3sendKeys(Keys.ENTER) 回车键(Enter)、sendKeys(Keys.F1) 键盘 F1
4sendKeys(Keys.CONTROL,'a') 全选(Ctrl+A)、sendKeys(Keys.CONTROL,'c') 复制(Ctrl+C)
5sendKeys(Keys.CONTROL,'x') 剪切(Ctrl+X)、sendKeys(Keys.CONTROL,'v') 粘贴(Ctrl+V)
  • 例如,发送回车键:
1WebElement button = driver.findElement(By.id("buttonId"));  
2button.sendKeys(Keys.ENTER);

模拟组合键操作

  • Selenium 还支持模拟组合键操作,如 Ctrl+C、Alt+F4 等。
  • 这需要使用 Actions 类来构建一系列动作,并通过 perform() 方法执行。
1Actions action = new Actions(driver);
2action.keyDown(Keys.CONTROL);  //按下 Ctrl 键
3action.keyUp(Keys.CONTROL);  //释放 Ctrl 键
  • 使用快捷键 Ctrl+Alt+a,可以通过下面语句来实现:
1Actions action = new Actions(driver);
2action.keyDown(Keys.CONTROL).keyDown(Keys.ALT)
3.sendKeys(“a”).keyUp(Keys.CONTROL).keyUp(Keys.ALT).perform();
  • keyDown(Key)方法的调用,如没有接着调用 keyUp(Key)或者 sendKeys(Keys.NULL) 来释放,按键将一样保持按住状态
  • keyDown(Key)方法的调用,如没有接着调用 keyUp(Key)或者 sendKeys(Keys.NULL) 来释放,按键将一样保持按住状态

测试代码

 1public  static void  keyTest(WebDriver webDriver) throws InterruptedException {
 2        webDriver.get("https://www.baidu.com");
 3
 4        // 定位到对应的元素
 5        WebElement input = webDriver.findElement(By.id("kw"));
 6
 7        //输入框输入内容
 8        input.sendKeys("苹果手机教程");
 9        Thread.sleep(2000);
10
11        //删除多输入的一个 程
12        input.sendKeys(Keys.BACK_SPACE);
13        Thread.sleep(2000);
14
15        //输入空格键+“教程”
16        input.sendKeys(Keys.SPACE);
17        input.sendKeys("教程");
18        Thread.sleep(2000);
19
20        //通过回车键盘来代替点击操作
21        input.sendKeys(Keys.ENTER);
22        Thread.sleep(2000);
23    }
  • 注意事项
    • 在发送键盘操作之前,请确保目标元素是可交互的(即可见且可点击)。
    • 如果元素在发送键盘操作之前处于隐藏或不可交互状态,可能会导致测试失败。
    • 在使用组合键时,请注意按键的顺序和释放的顺序,如果顺序不正确,可能会导致测试行为不符合预期。
  • 不同操作系统的键盘说明
 1windows:
 2send_keys(Keys.CONTROL, ‘a’) 方法用于全选文本,
 3send_keys(Keys.CONTROL, ‘c’) 方法用于复制文本,
 4send_keys(Keys.CONTROL, ‘x’) 方法用于剪切文本,
 5send_keys(Keys.CONTROL, ‘v’) 方法用于粘贴文本。
 6mac:
 7send_keys(Keys.COMMAND, ‘a’) 方法用于全选文本,
 8send_keys(Keys.COMMAND, ‘c’) 方法用于复制文本,
 9send_keys(Keys.COMMAND, ‘x’) 方法用于剪切文本,
10send_keys(Keys.COMMAND, ‘v’) 方法用于粘贴文本。

Selenium4.X 的显示等待和隐式等待

  • 需求
    • Web 应用通常通过异步加载(如 AJAX)来动态更新页面内容,页面元素可能不是立即可用的。
    • 当自动化测试脚本尝试访问或操作这些元素时,如果没有等待机制,可能会遇到定位失败、元素状态不正确等异常
    • Selenium4 等待主要解决以下问题:
      • 元素加载延迟
        • 当页面上的某些元素是通过异步请求(如 AJAX)加载的,这些元素可能不会立即出现在 DOM 中。
        • 网络波动或服务器响应延迟,页面上的某些内容可能需要一些时间才能加载。
        • 如果没有等待机制,测试脚本可能会在元素实际可用之前访问它,导致定位失败。
      • 依赖关系​:
        • 测试脚本中的操作可能依赖于前一步的结果或内容。
        • 例如,一个表单提交后,可能需要等待新页面加载完成才能继续执行后续操作。
      • 页面更新​:
        • JavaScript 可能会动态更改页面内容,如添加、删除或修改元素。
        • 如果没有等待,测试脚本可能会错过这些变化,导致测试失败。
  • Selenium 等待元素出现的方式有以下三种
    • 强制等待
      • 即线程休眠,在代码中强制当前正在执行的线程休眠(暂停执行)不管元素有没出现都固定时间
      • 前面案例操作中已经多次使用 TimeUnit.SECONDS.sleep(2);
    • 显式等待(Explicit Wait)
      • 通俗说就是死等,不灵活的等待,在指定的时间内一定要等到某个元素的出现或可操作的状态
      • 如果等不到,就一直等,直到在规定的时间之内都要操作的元素仍没找到,就抛出异常
      • 可以针对特定的元素或一组元素进行等待,提供了更灵活的等待机制,可以等待复杂的条件。
    • 隐式等待 (Implicit Wait)
      • 设置​全局等待时间,全部查找都会生效​,驱动初始化后就可以配置,在指定时间内轮询 DOM,直到找到元素或超时。
      • 一旦设置,在整个 WebDriver 对象实例的生命周期内都有效。
      • 适用于等待整个页面加载完毕。

代码示例

 1public static void waitTest(WebDriver webDriver)throws InterruptedException {
 2        //启动需要打开的网页
 3        webDriver.get("https://www.baidu.com");
 4
 5        // 创建显式等待对象,设置最大等待时间为5秒,直到能搜索栏元素可以为止
 6        WebDriverWait wait = new WebDriverWait(webDriver, Duration.ofSeconds(5));
 7        // 使用ExpectedConditions定义等待条件,例如元素可见性
 8        wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("kw")));
 9
10        //隐式等待,可以用一个不存在的元素位置进行测试
11        //webDriver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));
12        //webDriver.findElement(By.id("kw1")).sendKeys("小滴课堂官网");
13
14        //输入元素 sendKey
15        webDriver.findElement(By.id("kw")).sendKeys("小滴课堂官网");
16
17        //提交元素  submit
18        webDriver.findElement(By.id("su")).submit();
19        String text = webDriver.findElement(By.id("su")).getAttribute("value");
20        System.out.println("text======"+text);
21    }

Selenium4.X 进阶难点攻克

  • 需求
    • 自动化测试过程中会有打开不同网页的操作
    • 网页操作时会打开新窗口,不同窗口需要如何进行切换?
  • 不同窗口的切换
    • 自动化脚本通过识别浏览器窗口的属性用句柄 handle 来识别不同窗口
    • 窗口句柄 handle 是窗口的唯一标识,是窗口的唯一 ID
    • 通过 webDriver.getWindowHandles() 获取窗口全部具柄
    • 默认是第一个打开窗口,通过 webDriver.switchTo().window() 传入某个窗口句柄,切换到对应窗口

代码示例

 1public static void windowTest(WebDriver webDriver)throws InterruptedException {
 2        //打开网页
 3        webDriver.get("https://www.baidu.com");
 4        String currentHandle = webDriver.getWindowHandle();
 5        System.out.println("currentHandle===="+currentHandle);
 6        //点击百度的新闻页面
 7        webDriver.findElement(By.cssSelector("#s-top-left > a:nth-child(1")).click();
 8        // getWindowHandles获取全部窗口句柄
 9        Set<String> handles = webDriver.getWindowHandles();
10        String newHandle = "";
11        for(String handle : handles){
12            System.out.println("handle===="+handle);
13            //记录最后一个窗口的具柄
14            newHandle = handle;
15        }
16        TimeUnit.SECONDS.sleep(3);
17        //切换到新窗口,没调用默认还是第一个窗口,则定位新闻窗口的输入框元素会失败
18        webDriver.switchTo().window(newHandle);
19        //定位新闻窗口的输入框
20        webDriver.findElement(By.id("ww")).sendKeys("小滴课堂");
21    }

输出

1currentHandle====3345B9414EBCE6583025396E0852923A
2handle====3345B9414EBCE6583025396E0852923A
3handle====C442F9AA2E373211A4D037230C6121C6

iframe 实战自动登录 126 邮箱

什么是 iframe

  • iframe(Inline Frame)是 HTML 文档中的一个元素,允许在当前 HTML 页面中嵌入另一个 HTML 页面。
  • 其基本的用途是将另一个 HTML 文档嵌入到主文档中。
  • 就是一个网页可以嵌套到另一个网页中,可以嵌套很多层
  • 使用 selenium 操作浏览器时,如果需要操作 iframe 中的元素,首先需要切换到对应的内联框架中。
  • Selenium 给提供了三个重载的方法,进行操作 iframe
1// 方法一:通过 iframe的索引值,在页面中的位置
2webDriver.switchTo().frame(index);
3// 方法二:通过 iframe 的name 或者id
4webDriver.switchTo().frame(nameOrId);
5// 方法三:通过iframe 对应的webElement        
6webDriver.switchTo().frame(frameElement);

实战(如果站点失效或者变动,可以自己寻找其他站点测试)

  • 采用 126 邮箱站点进行测试
  • 注意:站点有动态 id 或者没有 id 和 name 等属性,可以用 xpath 或者 CSS 定位解决
 1public static void iframeTest(WebDriver webDriver) throws InterruptedException {
 2        webDriver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));
 3        //打开网站
 4        webDriver.get("https://www.126.com/");
 5
 6        //需要切换到对应的iframe才可以
 7        WebElement element = webDriver.findElement(By.xpath("//div[@id='loginDiv']/iframe"));
 8
 9        webDriver.switchTo().frame(element);
10
11        //定位账号输入框(如果站点有动态id,则不能使用xpath)
12        webDriver.findElement(By.xpath("//div[@class='u-input box']/input[@name='email']")).sendKeys("wcsb19900116");
13        webDriver.findElement(By.xpath("//div[@class='u-input box']/input[@name='password']")).sendKeys("password123");
14
15        //点击登录按钮
16        WebElement dologin = webDriver.findElement(By.id("dologin"));
17        System.out.println(dologin.getText());
18        dologin.click();
19    }

【保留现场】Selenium4.X 的快照截图

  • 什么是 Selenium 的快照截图
    • 自动化测试的时候,没有人工进行观看,用例执行失败如何进行发现?
    • 如果遇到有错误信息等,如何保存当前页面的截图,方便后续排查?
    • 快照截图功能是指 Selenium 自动化测试工具在测试过程中捕获浏览器窗口当前显示内容的图像,
    • 是 Selenium 在测试或调试过程中,为了保存当前浏览器窗口的可见内容而提供的一种功能。
    • 通常用于分析页面布局、验证页面元素的存在或状态,在测试失败时捕获页面状态以供后续分析。
  • 网页快照截图
    • 通过 API (TakesScreenshot) webDriver).getScreenshotAs(OutputType.FILE)

测试代码

 1public static void screenshotTest(WebDriver webDriver) throws IOException, InterruptedException {
 2        webDriver.get("https://baidu.com");
 3        webDriver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));
 4        webDriver.findElement(By.id("kw")).sendKeys("苹果手机1000");
 5
 6        //点击搜索
 7        webDriver.findElement(By.cssSelector("#su")).click();
 8        //等待搜索结果加载完成后截图
 9        TimeUnit.SECONDS.sleep(1);
10
11        //将快照文件存储,指定截图的保存路径和文件名,修改为你想要保存的路径和文件名
12        File file = ((TakesScreenshot) webDriver).getScreenshotAs(OutputType.FILE);
13        String screenshotPath = "D:\\screenshot\\screenshot.png";
14        File target = new File(screenshotPath);
15        // 保存截图到指定路径
16        try (FileOutputStream out = new FileOutputStream(target)) {
17            byte[] buffer = new byte[1024];
18            FileInputStream fis = new FileInputStream(file);
19            int bytesRead;
20            while ((bytesRead = fis.read(buffer)) != -1) {
21                out.write(buffer, 0, bytesRead);
22            }
23            fis.close();
24        }
25    }

screenshot.png

Selenium4.X 下拉框 Select 处理

  • 自动化测试里面的下拉框操作

    • 在网页设计中,下拉框(也被称作下拉列表或者选择框)是一种用户界面控件
    • 下拉框通常在被点击时显示其包含的所有选项列表,在用户选择某一选项后,列表会收回,只显示用户所选择的那个选项。
    • 如果一个页面元素是一个下拉框(select),对应下拉框的操作,selenium 有专门的类 Select 进行处理。
    • 其中包含了单选和多选下拉框的各种操作,如获得所有的选项、选择某一项、取消选中某一项、是否是多选下拉框等
  • Selenium 提供了 Select 类用于操作下拉框

    • 实例化 Select 类 使用定位到的下拉框元素来实例化 Select 类。
      1Select select = new Select(selectElement);
      
    • 根据索引选择​:使用 selectByIndex(int index) 方法。索引是从 0 开始的。
      1select.selectByIndex(1); // 选择第二个选项
      
    • 根据值选择​:如果下拉框的选项有 value 属性,可以使用 selectByValue(String value) 方法。
      1select.selectByValue("yourOptionValue");
      
    • 根据可见文本选择​:根据选项的可见文本选择,使用 selectByVisibleText(String text) 方法。
      1select.selectByVisibleText("Your Option Text");
      
  • 获取所有选项​:使用 getOptions() 方法。

  • 获取第一个选中的选项​:使用 getFirstSelectedOption() 方法。

  • 获取所有选中的选项​:使用 getAllSelectedOptions() 方法(注意,这通常用于多选下拉框)。

  • 取消选择对于多选下拉框,使用 deselectAll() 方法来取消所有选项,然后使用 selectBy... 方法来重新选择想要的选项。

  • 其他方法 还提供了其他方法,如 isMultiple()(检查下拉框是否允许多选)和 getOptions()(获取所有选项的列表)。

image.png

image.png

测试代码

 1public static void selectTest(WebDriver webDriver) throws InterruptedException {
 2        //直接把html文件用浏览器打开,然后复制地址栏这里打开
 3        //webDriver.get("file:///Users/xdclass/Desktop/select.html");
 4
 5        //飞猫客网站
 6        webDriver.get("https://www.feimaoke.com");
 7
 8        // 创建WebDriverWait对象,设置超时时长为10秒
 9        WebDriverWait wait = new WebDriverWait(webDriver, Duration.ofSeconds(10));
10        wait.until(ExpectedConditions.elementToBeClickable(By.id("menu-item-116"))).click();
11
12        // 移动光标(IT互联网)
13        Actions actions = new Actions(webDriver);
14        WebElement webElement = webDriver.findElement(By.id("menu-item-116"));
15        actions.moveToElement(webElement).perform();
16        TimeUnit.SECONDS.sleep(1);
17
18        //下拉光标(SEO教程)
19        WebElement webElement2 = webDriver.findElement(By.id("menu-item-117"));
20        actions.moveToElement(webElement2).click().perform();
21
22
23//        WebElement element = webDriver.findElement(By.id("mySelect"));
24//        Select select = new Select(element);
25//        List<WebElement> options = select.getOptions();
26//        for (WebElement option : options) {
27//            String text = option.getText();
28//            System.out.println(text);
29//        }
30//
31//        TimeUnit.SECONDS.sleep(2);
32//        //根据选项的可见文本选择
33//        select.selectByVisibleText("mysql");
34//
35//        TimeUnit.SECONDS.sleep(2);
36//        //根据索引选择,从0开始
37//        select.selectByIndex(1);
38//
39//        //根据value进行选择
40//        TimeUnit.SECONDS.sleep(2);
41//        select.selectByValue("4");
42//
43//        //判断是不是多选的选择框返回boolean值
44//        System.out.println(select.isMultiple());
45    }

Selenium4.X 弹窗 Alert 处理

  • 什么是 Alert

    • 操作 alert、confirm 弹出框,可以通过 Alert 对象来进行操作,Alert 类包含了确认、取消、输入和获取弹出窗内容。
    • Alert 对应属性和方法
    方法 描述
    alert.getText() 获取弹出框内容。
    alert.accept() 接受弹窗的提示,相当于点击确认按钮。
    alert.dismiss() 取消提示窗。
    alert.sendKeys(String s) 给弹窗输入内容。
  • 不同弹窗使用流程

    • 触发弹出框
      • 弹出框是由页面上的某些操作触发的,比如点击一个按钮或执行某些 JavaScript 代码。
      • 需要确保在执行下一步之前弹出框已经显示
    • 切换到弹出框
      • 使用 WebDriverswitchTo().alert() 方法来切换到弹出框。
      • 返回一个 Alert 对象,可以通过这个对象与弹出框进行交互。
1select.selectByVisibleText("Your Option Text");

处理 alert 弹出框​:

  • alert 弹出框通常只包含一条消息和一个“确定”按钮,可以使用 alert.accept() 方法来点击“确定”按钮
1alert.accept();

处理 confirm 弹出框

  • confirm 弹出框包含一个消息、一个“确定”按钮和一个“取消”按钮。
  • 可以使用 alert.accept() 来点击“确定”按钮,或者使用 alert.dismiss() 来点击“取消”按钮。
1// 点击“确定”按钮  
2alert.accept();  
3  
4// 或者点击“取消”按钮  
5alert.dismiss();

测试代码

 1public static void alertTest(WebDriver webDriver) throws InterruptedException {
 2        //直接把html文件用浏览器打开,然后复制地址栏这里打开
 3        webDriver.get("file:///Users/xdclass/Desktop/select.html");
 4
 5        // 创建WebDriverWait对象,设置超时时长为10秒
 6        WebDriverWait wait = new WebDriverWait(webDriver, Duration.ofSeconds(10));
 7        wait.until(ExpectedConditions.elementToBeClickable(By.id("alert_btn"))).click();
 8        //处理alert
 9        Alert alert = webDriver.switchTo().alert();
10        System.out.println("getText()======"+alert.getText());
11        TimeUnit.SECONDS.sleep(2);
12        alert.accept();
13
14        //处理confirm
15        webDriver.findElement(By.id("confirm_btn")).click();
16        Alert confirm = webDriver.switchTo().alert();
17        TimeUnit.SECONDS.sleep(2);
18        // 点击“确定”按钮
19        confirm.accept();
20        // 或者点击“取消”按钮
21        //confirm.dismiss();
22    }
  • 注意事项
    • 不是所有的浏览器和浏览器驱动都支持 Alert
    • 特别是无头浏览器(如 Headless Chrome 或 PhantomJS)可能不支持弹出框的交互。
    • 在这种情况下,可能需要使用其他方法(如 JavaScript 执行器)来绕过弹出框或模拟用户的行为。
    • 弹出框可能会阻塞页面的其他操作,在自动化测试中处理弹出框时要特别小心,确保测试代码能够正确地与弹出框进行交互

Web 自动化操作之验证码常见解决方案

  • 需求
    • 进行 WebUI 自动化或爬虫的时候,不少站点都有风控策略,需要攻克这类问题才可以进行
    • 常见的问题有图像验证码、滑动验证码、ip 限制等,我们重点讲验证码方案
    • 这个也是高频面试题:WebUI 自动化测试里面,如果遇到验证码你会怎么处理?
  • 验证码
    • 在 Web 应用中,验证码作为一种安全机制,被广泛应用于用户登录、表单提交等场景,以防止自动化脚本或恶意程序的攻击
    • 主要目的是识别是否机器人操作,大量的机器人(爬虫)操作会向服务器发送大量无效请求,严重占用服务器资源
    • 验证码的存在给 WebUI 自动化测试带来了挑战,因为传统的自动化测试脚本无法直接处理验证码
  • 常见解决方案
    • 手动输入验证码
      • 这是最直接且常见的方法。当自动化测试脚本遇到验证码时,测试人员需要手动输入验证码以完成验证过程。
      • 优点​:简单直接,无需技术介入。
      • 缺点​:降低了测试的自动化程度,增加了人为干预和错误的可能性。
    • 使用万能验证码
      • 在测试环境中,可以设置一个固定的、已知的“万能验证码”,这样自动化脚本在需要验证时就可以使用这个固定的验证码。
      • 优点​:测试人员无需手动输入,提高了自动化程度。
      • 缺点​:存在安全风险,仅限于测试环境使用。
    • 读取并发送 cookies
      • 在用户成功登录后,获取相关的 cookies 信息。在后续的自动化操作中,使用这些 cookies 信息来跳过验证码验证。
      • 优点​:自动化程度高,无需处理验证码本身。
      • 缺点​:依赖于 cookies 的有效性和安全性,可能不适用于所有情况。
    • 图片识别验证码
      • 使用图像识别技术(如 OCR)来识别验证码图片中的字符或数字,并将识别结果自动输入到验证框中。
      • 可以使用如开源 OCR 库来进行图片验证码的识别
      • 优点​:高度自动化,减少了人为干预。
      • 缺点​:图像识别技术可能受到验证码复杂度和图片质量的影响,导致识别率不高。
    • 滑块验证码处理
      • 对于滑块验证码,需要模拟用户拖动滑块的行为来完成验证,这通常涉及到屏幕截图、图像分析和鼠标操作等技术。
      • 优点​:针对特定类型的验证码进行处理,适用于需要处理滑块验证码的场景。
      • 缺点​:实现复杂,可能需要针对不同网站和验证码类型进行定制化开发,成功率也不高
    • 结合多种策略
      • 在实际应用中,可以根据具体情况结合使用上述多种策略。
      • 例如,在测试环境中使用万能验证码,而在生产环境中使用图像识别技术或 cookies 来处理验证码。

自动化测试之登录解决方案-绕过验证码

  • 需求
    • 当下互联网下多个网站,登录的时候除了需要账号密码,还需要图形验证码才可以成功操作
    • 对于要登录才可以测试的网页,则需要跳过验证码,常见方案是手工增加 cookie
    • 测试需求:利用代码里面增加 Cookie,访问小滴课堂登录后的页面
  • 什么是 Cookie
    • 服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上
    • 用于告知服务端两个请求是否来自同一浏览器,保持用户的登录状态
    • Cookie 存储在客户端(用户的浏览器)上。
    • 最常见的用途之一是跟踪会话,尤其是身份验证和个性化设置。
    • 例如,许多网站在用户登录后使用 Cookie 来记住用户的身份,以便用户可以在不同页面之间导航而无需重新登录
  • 案例实战(学思路最关键,大家可以利用其他站点测试,​网站也会经常改版,不要卡这个点​)
    • 分析站点功能
    • 判断登录检验方案
    • 测试 Selenium 读取 Cookie

image.png

image.png

案例实战(学思路最关键,可以利用其他站点测试,​网站也会经常改版,不要卡这个点​)

  • 分析站点功能
  • 判断登录检验方案
  • 测试 Selenium 读取 Cookie
 1public static void cookieTest(WebDriver webDriver) throws Exception {
 2        webDriver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));
 3        webDriver.get("https://xdclass.net/");
 4        TimeUnit.SECONDS.sleep(3);
 5        //关闭弹窗
 6        webDriver.findElement(By.xpath("/html/body/div/div/div[2]/div/div/a/div/div/button/span")).click();
 7        TimeUnit.SECONDS.sleep(1);
 8
 9        //出现登录窗口
10        webDriver.findElement(By.xpath("/html/body/div/div/div[1]/div[2]/div[1]/div[2]/div/span[1]")).click();
11        TimeUnit.SECONDS.sleep(2);
12        //输入账号密码
13        webDriver.findElement(By.id("form_item_account")).sendKeys("15221114839");
14        webDriver.findElement(By.id("form_item_password")).sendKeys("xxxxx");
15        TimeUnit.SECONDS.sleep(2);
16
17        //点击立刻登录
18        webDriver.findElement(By.xpath("/html/body/div/div/div[1]/div[2]/div[3]/div/div/div[2]/form/div[4]/div/div/div/button")).click();
19        TimeUnit.SECONDS.sleep(2);
20
21        Set<Cookie> cookies = webDriver.manage().getCookies();
22        for (Cookie cookie : cookies) {
23            System.out.println("Cookie Name: " + cookie.getName() +" Cookie Value: " + cookie.getValue());
24        }
25    }

输出

1Cookie Name: user Cookie Value: %7B%22token%22%3A%22dcloud-clienteyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ4ZGNsYXNzIiwiaGVhZF9pbWciOiJodHRwczovL3hkLXZpZGVvLXBjLWltZy5vc3MtY24tYmVpamluZy5hbGl5dW5jcy5jb20veGRjbGFzc19wcm8vZGVmYXVsdC9oZWFkX2ltZy8xMC5qcGVnIiwiYWNjb3VudF9pZCI6MTA1MjksInVzZXJuYW1lIjoiY2VzdGJvbiIsInJvbGUiOiJGT1JFVkVSX1ZJUCIsIm1lZGFsIjoiRk9SRVZFUl9WSVAiLCJpYXQiOjE3MTk1NTY0NTMsImV4cCI6MTcyMDE2MTI1M30.oldEj6_Ikj0nnc5aWG_-lJpyVQMkuGmeBU9UKDQfETA%22%2C%22isVip%22%3Atrue%2C%22isLogin%22%3Atrue%2C%22orderstate%22%3A%22%22%2C%22personalInfo%22%3A%7B%22accountId%22%3A10529%2C%22socialId%22%3Anull%2C%22identityType%22%3Anull%2C%22identifier%22%3Anull%2C%22credential%22%3Anull%2C%22username%22%3A%22cestbon%22%2C%22headImg%22%3A%22https%3A%2F%2Fxd-video-pc-img.oss-cn-beijing.aliyuncs.com%2Fxdclass_pro%2Fdefault%2Fhead_img%2F10.jpeg%22%2C%22slogan%22%3A%22%22%2C%22sex%22%3Anull%2C%22city%22%3A%22%E4%B8%AD%E5%9B%BD%22%2C%22sum%22%3Anull%2C%22role%22%3A%22FOREVER_VIP%22%2C%22learnTime%22%3A192829%2C%22vipRank%22%3A1252%2C%22coin%22%3A28%2C%22vipExpired%22%3Anull%2C%22tag%22%3A%22%22%2C%22position%22%3Anull%2C%22company%22%3Anull%2C%22appid%22%3A%22vvhWQJ9gpQbeIOJagb%22%2C%22appsecret%22%3A%221M5Y5G94V5KxjIOPZSYEAsWo2BGWGOKY%22%2C%22acl%22%3Anull%2C%22disabled%22%3A%22ON%22%2C%22phone%22%3A%2215221114839%22%2C%22email%22%3Anull%2C%22bindWechat%22%3Afalse%2C%22medal%22%3A%22FOREVER_VIP%22%2C%22setPassword%22%3Atrue%2C%22gmtCreate%22%3Anull%2C%22gmtModified%22%3A%222024-06-28+13%3A32%3A16%22%2C%22avatar%22%3A%22https%3A%2F%2Fxd-video-pc-img.oss-cn-beijing.aliyuncs.com%2Fxdclass_pro%2Fdefault%2Fhead_img%2F10.jpeg%22%6D%6D
  • 需求
    • 使用浏览器或者 Selenium 提取到的 Cookie,配置代码
    • 访问某个课程,并且加入收藏夹
  • 编码实战(​注意:如果失效,可以用 xpath 或者 CSS 选择器,绝对定位获取元素进行操作​)
    • 进入小滴课堂首页
    • 代码里面增加 Cookie
    • 刷新当前页面
    • 进入课程中心
    • 进入商品详情页
    • 收藏商品
 1public static void loginTest(WebDriver webDriver) throws InterruptedException {
 2        //进入小滴课堂首页
 3        webDriver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));
 4        webDriver.get("https://xdclass.net/");
 5        TimeUnit.SECONDS.sleep(3);
 6        //关闭弹窗
 7        webDriver.findElement(By.xpath("/html/body/div/div/div[2]/div/div/a/div/div/button/span")).click();
 8        TimeUnit.SECONDS.sleep(2);
 9
10        //代码里面增加Cookie
11        String token = "%7B%22token%22%3A%22dcloud-clienteyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ4ZGNsYXNzIiwiaGVhZF9pbWciOiJodHRwczovL3hkLXZpZGVvLXBjLWltZy5vc3MtY24tYmVpamluZy5hbGl5dW5jcy5jb20veGRjbGFzc19wcm8vZGVmYXVsdC9oZWFkX2ltZy8xMC5qcGVnIiwiYWNjb3VudF9pZCI6MTA1MjksInVzZXJuYW1lIjoiY2VzdGJvbiIsInJvbGUiOiJGT1JFVkVSX1ZJUCIsIm1lZGFsIjoiRk9SRVZFUl9WSVAiLCJpYXQiOjE3MTk1NTg5NDcsImV4cCI6MTcyMDE2Mzc0N30.wyltpoxPU0GjJ1rVbB1z8EQmzlZuZ2V_mSpxjbRfEbE%22%2C%22isVip%22%3Atrue%2C%22isLogin%22%3Atrue%2C%22orderstate%22%3A%22%22%2C%22personalInfo%22%3A%7B%22accountId%22%3A10529%2C%22socialId%22%3Anull%2C%22identityType%22%3Anull%2C%22identifier%22%3Anull%2C%22credential%22%3Anull%2C%22username%22%3A%22cestbon%22%2C%22headImg%22%3A%22https%3A%2F%2Fxd-video-pc-img.oss-cn-beijing.aliyuncs.com%2Fxdclass_pro%2Fdefault%2Fhead_img%2F10.jpeg%22%2C%22slogan%22%3A%22%22%2C%22sex%22%3Anull%2C%22city%22%3A%22%E4%B8%AD%E5%9B%BD%22%2C%22sum%22%3Anull%2C%22role%22%3A%22FOREVER_VIP%22%2C%22learnTime%22%3A192829%2C%22vipRank%22%3A1252%2C%22coin%22%3A28%2C%22vipExpired%22%3Anull%2C%22tag%22%3A%22%22%2C%22position%22%3Anull%2C%22company%22%3Anull%2C%22appid%22%3A%22vvhWQJ9gpQbeIOJagb%22%2C%22appsecret%22%3A%221M5Y5G94V5KxjIOPZSYEAsWo2BGWGOKY%22%2C%22acl%22%3Anull%2C%22disabled%22%3A%22ON%22%2C%22phone%22%3A%2215221114839%22%2C%22email%22%3Anull%2C%22bindWechat%22%3Afalse%2C%22medal%22%3A%22FOREVER_VIP%22%2C%22setPassword%22%3Atrue%2C%22gmtCreate%22%3Anull%2C%22gmtModified%22%3A%222024-06-28+13%3A32%3A16%22%2C%22avatar%22%3A%22https%3A%2F%2Fxd-video-pc-img.oss-cn-beijing.aliyuncs.com%2Fxdclass_pro%2Fdefault%2Fhead_img%2F10.jpeg%22%6D%6D";
12        // 创建和设置Cookie
13        Cookie authCookie = new Cookie.Builder("user", token)
14                // 需要设置为您要登录的网站域名
15                .domain("xdclass.net")
16                // 通常是"/"
17                .path("/")
18                // 可以加其它属性,如 isHttpOnly, isSecure, expiry 等
19                .build();
20
21        //添加Cookie到当前的session
22        webDriver.manage().addCookie(authCookie);
23
24        //再次访问需要登录才能访问的页面,这时候应该已经“登录”了
25        webDriver.navigate().refresh();
26        TimeUnit.SECONDS.sleep(2);
27
28        //关闭弹窗
29//        webDriver.findElement(By.xpath("/html/body/div/div/div[2]/div/div/a/div/div/button/span")).click();
30//        TimeUnit.SECONDS.sleep(1);
31
32        //进入课程中心
33        webDriver.findElement(By.xpath("/html/body/div[1]/div/div[1]/div[2]/div[1]/div[1]/a[2]")).click();
34        TimeUnit.SECONDS.sleep(3);
35
36        //获取全部窗口句柄
37        Set<String> windowHandles = webDriver.getWindowHandles();
38        String newHandle = "";
39        for (String windowHandle : windowHandles) {
40            //记录最后一个窗口的句柄
41            newHandle = windowHandle;
42            System.out.println(windowHandle);
43        }
44
45        //切换到课程中心 新窗口,没调用默认还是第一个窗口,则定位窗口的输入框元素会失败
46        webDriver.switchTo().window(newHandle);
47        webDriver.findElement(By.cssSelector("#__nuxt > div > div.main-container > div > div > div.video-list > div.left > div:nth-child(1) > div > div.cards > a:nth-child(1)")).click();
48        TimeUnit.SECONDS.sleep(3);
49
50        //切换课程详情页窗口
51        String lastWindowHandle = webDriver.getWindowHandles().stream().reduce((first, second) -> second).orElse(null);
52        webDriver.switchTo().window(lastWindowHandle);
53        TimeUnit.SECONDS.sleep(3);
54
55        //收藏课程
56        webDriver.findElement(By.xpath("/html/body/div/div/div[2]/div/div[2]/div[1]/div[1]/div[4]/div[2]")).click();
57    }

测试框架 TestNG

  • 什么是 TestNG 框架

    • 是一个与测试业务逻辑实现无关的测试框架,主要用于 Java 应用程序的自动化测试。
    • TestNG 类似于 JUnit,但不是 Junit 的拓展,也丰富了断言等功能
    • 提供一整套测试管理的解决方案,使用注解 来定义和管理测试方法、测试前置和后置操作等
    • 使用 TestNG 可以非常的管理被测系统所有测试脚本,让自动化测试代码更加高效且易于管理
    • 官网地址:https://testng.org/
  • 核心特性

    • 注解支持​:TestNG 使用 Java 注解来定义测试方法、测试组、测试套件等,简化了测试代码的编写和管理。
    • 测试套件​:可以将多个测试用例组织成一个测试套件,方便批量执行和结果统计。
    • 测试组​:支持将测试用例划分为不同的组,可以基于组来执行测试用例或设置依赖关系。
    • 执行顺序控制​:通过优先级、依赖关系等方式来控制测试用例的执行顺序。
    • 参数化测试​:支持通过数据提供器(DataProvider)来实现参数化测试,简化测试用例的编写和复用。
    • 测试结果报告​:提供多种格式的测试结果报告,包括 HTML、XML 等,方便测试结果的分析和分享。
  • 快速上手

    • IDEA 安装插件
      • idea 默认已经安装 testng,
      • 检查是否安装:File ==> Settings ==>Plugins ==> 搜索 testng
    • 代码增加依赖
1<!-- testng -->
2        <dependency>
3            <groupId>org.testng</groupId>
4            <artifactId>testng</artifactId>
5            <version>7.10.2</version>
6            <scope>test</scope>
7        </dependency>

编写测试代码

 1package com.soulboy;
 2
 3import org.testng.Assert;
 4import org.testng.annotations.Test;
 5
 6public class testng {
 7    @Test
 8    public void verifySetup()
 9    {
10        System.out.println("TestNG setup is working fine");
11    }
12
13    @Test
14    public void testAssert() {
15        System.out.println("这个是一个断言测试");
16        int a = 9;
17        int b = 100;
18        Assert.assertTrue(a > b, "判断错误,出问题啦");
19    }
20}

image.png

  • 使用方式支持注解和 XML 两种

    • 注解方式
      • 在 TestNG 中,注解被用于标记测试类、测试方法、测试前置和后置操作等,以定义测试的行为和顺序。
      • 优点
        • 简洁性​:注解的使用可以减少 XML 配置文件的冗余,使测试代码更加简洁明了。
        • 类型安全​:注解在编译时就能进行类型检查,减少了运行时错误的可能性。
        • 易于维护​:在中小项目中,使用注解可以简化配置,提高开发效率。
      • 缺点
        • 分散性​:注解分散在多个类中,不利于统一管理和维护。
        • 修改困难​:如果需要修改注解的配置,可能需要修改源代码,这可能导致额外的编译和部署工作。
        • 灵活性​:在实现复杂的逻辑时,注解可能没有 XML 配置那么强大和灵活。
    • XML 方式
      • XML 配置文件是 TestNG 中用于定义测试套件、测试组、测试类等的重要文件
      • 优点
        • 集中管理​:XML 配置文件将所有测试相关的配置集中在一起,方便统一管理和维护。
        • 灵活性​:XML 配置可以支持复杂的测试逻辑和依赖关系,更加灵活和强大。
        • 可扩展性​:XML 配置具有良好的可扩展性,可以方便地添加新的测试类或测试方法。
      • 缺点
        • 冗余性​:相对于注解,XML 配置文件可能会显得冗余和复杂。
        • 解析成本​:客户端和服务器端都需要花费大量代码来解析 XML,可能导致代码变得复杂且不易维护。
        • 修改成本​:修改 XML 配置文件不需要修改源代码,但可能需要重新编译和部署测试套件。
  • 选择原则​:

    • 对于中小项目或简单的测试场景,使用注解可能更加简洁和高效;
    • 而对于大型项目或复杂的测试场景,使用 XML 配置可能更加灵活和强大。
    • 也取决于团队之前测试的习惯方式,可以根据需要混合使用注解和 XML 配置
    • 我们更习惯使用注解方式,类似 Spring 框架

TestNG 常用注解

基本测试注解

  • ​@Test:标记一个类或方法作为测试的一部分。

方法级别生命周期注解

  • ​@BeforeMethod​:在每个测试方法运行之前运行。
  • ​@AfterMethod​:在每个测试方法运行之后运行。

类级别生命周期注解

  • ​@BeforeClass:在当前类中所有方法运行之前调用,只运行一次。
  • ​@AfterClass​:在当前类中所有方法运行之后调用,只运行一次。

套件级别生命周期注解

  • ​@BeforeSuite​:带有此注解的方法会在一个测试套件执行之前执行一次。
  • ​@AfterSuite​:带有此注解的方法会在一个测试套件执行之后执行一次。

数据提供注解

  • ​@DataProvider:用于为测试方法提供数据,支持参数化测试。
  • ​@Test(dataProvider = "XXX")​:指定使用哪个数据提供器。
 1@DataProvider(name = "testData")  
 2public Object[][] dpTest() {  
 3    return new Object[][] {  
 4        {1, "Lucy"},  
 5        {2, "Jack"}  
 6    };  
 7}  
 8  
 9@Test(dataProvider = "testData")  
10public void testDataDriven(Integer id, String name) {  
11    System.out.println("编号: " + id + ", 姓名: " + name);  
12}

image.png

其他不常用的注解

  • @Test(groups = "XXX"):将测试方法分组,以便可以按组运行测试。
  • @BeforeGroups("XXX") 和 ​**@AfterGroups("XXX")**​:在指定组的第一个和最后一个测试方法之前/之后运行。
  • @BeforeTest 和 ​**@AfterTest**​:在 XML 文件中的每个 <test> 标签执行前/后运行。这些注解通常与测试套件配置相关。

TestNG 作用域注解执行顺序

image.png

 1public class VerifyOrder {
 2    @Test
 3    public void testCase1() {
 4        System.out.println("这个是测试用例1执行");
 5    }
 6
 7    @Test
 8    public void testCase2() {
 9        System.out.println("这个是测试用例2执行");
10    }
11
12    @BeforeMethod
13    public void beforeMethod() {
14        System.out.println("这个是beforeMethod执行");
15    }
16
17    @AfterMethod
18    public void afterMethod() {
19        System.out.println("这个是afterMethod执行");
20
21    }
22
23    @BeforeClass
24    public void beforeClass() {
25        System.out.println("这个是BeforeClass执行");
26
27    }
28
29    @AfterClass
30    public void afterClass() {
31        System.out.println("这个是afterClass执行");
32    }
33
34    @BeforeTest
35    public void beforeTest() {
36        System.out.println("这个是beforeTest执行");
37
38    }
39
40    @AfterTest
41    public void afterTest() {
42        System.out.println("这个是afterTest执行");
43    }
44
45    @BeforeSuite
46    public void beforeSuite() {
47        System.out.println("这个是beforeSuite执行");
48    }
49
50    @AfterSuite
51    public void afterSuite() {
52        System.out.println("这个是afterSuite执行");
53    }
54
55}

TestNG 提供了多种方式来控制测试用例的执行顺序

  • 默认执行顺序
    • 如果没有明确指定,TestNG 默认会根据测试用例方法的名称进行排序和执行
    • 按照字典顺序(即字母和数字的顺序)来执行。
  • 使用 @Test(priority=...) 注解
    • @Test 注解中,可以通过设置 priority 属性来指定测试用例的优先级。
    • 数值越小,优先级越高,即测试用例会先执行
    • 例如,@Test(priority=1) 的测试用例会比 @Test(priority=2) 的测试用例先执行。
  • 使用 dependsOnMethods 属性
    • 通过在 @Test 注解中使用 dependsOnMethods 属性,可以指定一个或多个测试用例的依赖关系。
    • 一个测试用例的执行依赖于另一个或多个测试用例的执行结果。
    • 被依赖的测试用例会首先执行。例如:测试用例 B 会在测试用例 A 执行完毕后执行。
1@Test  
2public void testA() {  
3    // 测试用例A的代码  
4}  
5
6@Test(dependsOnMethods = "testA")  
7public void testB() {  
8    // 测试用例B的代码,它依赖于testA的执行结果  
9}
  • 注意事项
    • 当使用 dependsOnMethods 时,需要确保被依赖的测试用例或组总是能够成功执行,否则依赖它们的测试用例将不会被执行。
    • 在复杂的测试场景中,过度依赖和硬编码的执行顺序可能会使测试变得脆弱和难以维护。
    • 在可能的情况下,应尽量避免过强的依赖和固定的执行顺序。

项目实战之企业场景用例编写

  • 需求

    • 后续进行项目案例实战,使用 TestNG+Selenium4.X 集成自动化 WebUI 测试
    • 比如对豆瓣网进行测试时,可以设计多个测试用例来覆盖不同的功能和业务场景。
    • 企业工作中也是类似编写用例和进行集成测试,掌握常见的用例编写规范

    image.png

  • UI 自动化测试用例编写规范

    • 一个脚本对应一个完整场景
      • 每个自动化测试脚本应覆盖一个完整的用户场景,例如从用户登录到退出系统的整个过程。
    • 单一功能点验证
      • 每个脚本应专注于验证一个特定的功能点,避免在一个脚本中验证多个功能。
    • 正向逻辑验证为主
      • 优先验证功能的正向逻辑,避免过度考虑逆向逻辑的验证,以减少脚本的复杂性和脆弱性。
    • 脚本独立性
      • 确保每个脚本都是独立的,不依赖于或影响其他脚本的执行。
    • 数据还原
      • 如果测试过程中修改了数据,测试结束后应对数据进行还原,保持测试环境的清洁。
    • 验证点明确
      • 在脚本中只针对明确的验证点进行验证,避免对整个脚本的每一步都进行验证。
    • POM(Page Object Model)结构
      • 设计遵循 POM 结构,将用例层、业务逻辑层和 Page 层明确分离。
    • 页面设计规则
      • 每个页面一个类,类名以 Page 结尾;页面辅助控件和逻辑设计为接口,并提供默认实现。
    • 参数封装
      • 除简单逻辑外,业务逻辑的参数使用 Java Bean 和枚举封装,以适应产品设计的变化。
    • 状态码和文案
      • 使用枚举定义状态码、产品特定文案等,以规范入参
  • 常用用例编写案例说明

    • 测试用例一:用户登录功能

      • 测试目标​:验证用户登录功能的正确性。
      • 前置条件​:豆瓣网已注册用户,存在有效账号和密码。
      • 测试步骤​:
        • 打开豆瓣网首页。
        • 点击登录按钮,进入登录页面。
        • 输入正确的用户名和密码。
        • 点击登录按钮。
      • 预期结果​:
        • 成功登录后,跳转到用户主页或上次访问的页面。
        • 页面右上角显示登录用户的信息。
      • 实际结果​:记录实际登录后的页面跳转情况和用户信息显示情况。
    • 测试用例二:电影搜索功能

      • 测试目标​:验证电影搜索功能的正确性。
      • 前置条件​:豆瓣网存在电影搜索功能。
      • 测试步骤​:
        • 打开豆瓣网首页。
        • 进入电影搜索页面。
        • 输入电影名称或关键词。
        • 点击搜索按钮。
      • 预期结果​:
        • 搜索结果页面显示与输入关键词相关的电影列表。
        • 电影列表包含电影标题、评分、导演、主演等信息。
      • 实际结果​:记录实际搜索结果页面的内容和展示情况。
    • 测试用例三:电影评论功能

      • 测试目标​:验证电影评论功能的正确性。
      • 前置条件​:已登录豆瓣网账号,选择一部电影进入详情页面。
      • 测试步骤​:
        • 进入电影详情页面。
        • 滚动到评论区域,查看已有评论。
        • 点击写评论按钮,输入评论内容。
        • 点击提交按钮。
      • 预期结果​:
        • 评论成功提交后,在页面上能够看到新添加的评论。
        • 新评论包含评论者头像、昵称、评论内容、时间等信息。
      • 实际结果​:记录评论提交后的页面显示情况和新评论的展示情况。
    • 测试用例四:豆瓣读书模块功能

      • 测试目标​:验证豆瓣读书模块功能的正确性。
      • 前置条件​:豆瓣网存在读书模块,包含书籍搜索、书籍详情、书评等功能。
      • 测试步骤​(以书籍搜索为例):
        • 进入豆瓣读书页面。
        • 在搜索框中输入书籍名称或关键词。
        • 点击搜索按钮。
      • 预期结果​:
        • 搜索结果页面显示与输入关键词相关的书籍列表。
        • 书籍列表包含书籍封面、标题、作者、评分等信息。
      • 实际结果​:记录实际搜索结果页面的内容和展示情况。
    • 测试用例五:豆瓣同城活动功能

      • 测试目标​:验证豆瓣同城活动功能的正确性。
      • 前置条件​:豆瓣网存在同城活动模块,包含活动搜索、活动详情、报名等功能。
      • 测试步骤​(以活动搜索为例):
        • 进入豆瓣同城页面。
        • 在搜索框中输入活动类型或关键词。
        • 点击搜索按钮。
      • 预期结果​:
        • 搜索结果页面显示与输入关键词相关的活动列表。
        • 活动列表包含活动名称、时间、地点、参与人数等信息。
      • 实际结果​:记录实际搜索结果页面的内容和展示情况。
  • 注意事项

    • 在实际测试中,可能需要结合豆瓣网的实际情况和页面变化对测试用例进行调整。
    • 对于涉及用户行为和安全性的测试,需要遵循相关测试准则和平台要求。
    • 测试过程中需要详细记录实际结果和遇到的问题,以便后续分析和改进

TestNG+Selenium4.X 豆瓣网自动化测试实战

  • 需求介绍
    • 对豆瓣网进行 UI 自动化测试,设计多个测试用例来覆盖不同的功能和业务场景。
    • 使用 TestNG+Selenium4.X 集成,编写多个用例,包括断言使用等
    • 采用适当封装组件,结合 OOP 思想
    • 注意事项:豆瓣网可能改网页结构,如果你们测试的时候,定位元素不一样,可以换其他网站或者方式

SeleniumBase

 1package com.soulboy;
 2
 3import org.openqa.selenium.WebDriver;
 4import org.openqa.selenium.chrome.ChromeDriver;
 5import org.openqa.selenium.chrome.ChromeOptions;
 6
 7public class SeleniumBase {
 8
 9    protected WebDriver webDriver;
10
11    public void setUp() {
12        //指定驱动路径
13        System.setProperty("webdriver.chrome.driver","C:\\Tools\\chromedriver-win64\\chromedriver.exe");
14        // 谷歌驱动
15        ChromeOptions options = new ChromeOptions();
16        // 允许所有请求
17        options.addArguments("--remote-allow-origins=*");
18        webDriver = new ChromeDriver(options);
19        // 最大化浏览器
20        webDriver.manage().window().maximize();
21    }
22
23    public void tearDown() {
24        if (webDriver != null) {
25            webDriver.quit();
26        }
27    }
28
29    // 封装其他常用的方法,比如导航到URL、查找元素等
30}

AssertMessage

1package com.soulboy;
2
3public class AssertMessage {
4    public static final String ERROR_TITTLE_MESSAGE = "标题断言失败";
5    public static final String ERROR_URL_MESSAGE = "URL断言失败";
6    public static final String ERROR_CONTEXT_MESSAGE = "内容断言失败";
7}

TestReadBookPage

  1package com.soulboy;
  2
  3import org.openqa.selenium.By;
  4import org.openqa.selenium.WebElement;
  5import org.testng.Assert;
  6import org.testng.annotations.AfterClass;
  7import org.testng.annotations.BeforeClass;
  8import org.testng.annotations.Test;
  9
 10import java.time.Duration;
 11import java.util.concurrent.TimeUnit;
 12
 13public class TestReadBookPage extends SeleniumBase {
 14
 15    /**
 16     * 在所有测试执行前进行初始化操作。
 17     * 初始化浏览器驱动,设置隐式等待时间,并导航到豆瓣首页。
 18     */
 19    @BeforeClass
 20    public void setupClass() {
 21        setUp(); // 调用父类的初始化方法
 22        webDriver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
 23        webDriver.get("https://www.douban.com/");
 24    }
 25
 26    /**
 27     * 在所有测试执行后进行清理操作。
 28     * 主要是为了调用父类的清理方法,确保资源正确释放。
 29     */
 30    @AfterClass
 31    public void tearDownClass() {
 32        tearDown(); // 调用父类的清理方法
 33    }
 34
 35    /**
 36     * 测试豆瓣首页的标题是否包含"豆瓣"。
 37     * 该测试优先级为1,确保在其他测试之前执行。
 38     */
 39    @Test(priority = 1)
 40    public void testHomePageTitle() throws InterruptedException {
 41        String title = webDriver.getTitle();
 42        System.out.println("Title: " + title);
 43        //断言
 44        Assert.assertTrue(title.contains("豆瓣"), AssertMessage.ERROR_TITTLE_MESSAGE);
 45        TimeUnit.SECONDS.sleep(2);
 46    }
 47
 48    /**
 49     * 首先点击进入读书页面,验证是否成功进入豆瓣读书页面
 50     * 该测试依赖于testHomePageTitle测试,只有在首页标题测试通过后才会执行。
 51     */
 52    @Test(priority = 2, dependsOnMethods = "testHomePageTitle")
 53    public void testEnterBook() throws InterruptedException {
 54        //点击读书
 55        webDriver.findElement(By.xpath("/html/body/div[1]/div[2]/div[1]/ul/li[1]/a")).click();
 56
 57        //切换窗口
 58        webDriver.getWindowHandles().forEach(window -> webDriver.switchTo().window(window));
 59        String currentUrl = webDriver.getCurrentUrl();
 60        System.out.println("Current URL: " + currentUrl);
 61        Assert.assertTrue(currentUrl.contains("book.douban.com"), AssertMessage.ERROR_URL_MESSAGE);
 62        TimeUnit.SECONDS.sleep(2);
 63    }
 64
 65    /**
 66     * 测试搜索功能,搜索关键词"java",验证是否进入搜索结果页面。
 67     * 该测试优先级为3,旨在测试搜索功能的基本可用性。
 68     */
 69    @Test(priority = 3)
 70    public void testSearchBook() throws InterruptedException {
 71        //获取搜索框input元素,并输入java
 72        webDriver.findElement(By.id("inp-query")).sendKeys("java");
 73        //点击submit按钮
 74        webDriver.findElement(By.xpath("/html/body/div[2]/div[1]/div/div[2]/form/fieldset/div[2]/input")).click();
 75        //断言(通过title是否包含java字段)
 76        String title = webDriver.getTitle();
 77        System.out.println("Title: " + title);
 78        TimeUnit.SECONDS.sleep(2);
 79        Assert.assertTrue(title.contains("java"),AssertMessage.ERROR_TITTLE_MESSAGE);
 80
 81    }
 82
 83    /**
 84     * 验证搜索结果中是否包含"Java核心技术·卷I"这本书。
 85     * 该测试依赖于testSearchPage,确保搜索功能正常后验证搜索结果。
 86     */
 87    @Test(priority = 4)
 88    public void testSearchResultCount() throws InterruptedException {
 89        //获取 Java核心技术·卷I(原书第12版) : 开发基础 元素
 90        WebElement element = webDriver.findElement(By.xpath("/html/body/div[3]/div[1]/div/div[2]/div[1]/div[1]/div[3]/div/div/div[1]/a"));
 91        String text = element.getText();
 92        System.out.println(text);
 93        TimeUnit.SECONDS.sleep(2);
 94        //断言
 95        Assert.assertTrue(text.contains("Java核心技术·卷I"),AssertMessage.ERROR_CONTEXT_MESSAGE);
 96
 97    }
 98
 99    /**
100     *  Java核心技术·卷I(原书第12版)
101     * 该测试依赖于testSearchPage,确保搜索功能正常后验证搜索结果。
102     */
103    @Test(priority = 5)
104    public void clickBookDetail() throws InterruptedException {
105        //点击a链接,查看书籍详情
106        webDriver.findElement(By.xpath("/html/body/div[3]/div[1]/div/div[2]/div[1]/div[1]/div[3]/div/div/div[1]/a")).click();
107        TimeUnit.SECONDS.sleep(2);
108        //断言
109        Assert.assertTrue(webDriver.getTitle().contains("Java核心技术·卷I"),AssertMessage.ERROR_TITTLE_MESSAGE);
110
111    }
112
113}

作者:Soulboy