目录

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

路径

C:\Tools\chrome-win64

chromedriverwin64.zip

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

<dependencies>
        <!-- Selenium -->
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>4.10.0</version>
        </dependency>
   </dependencies>

控制代码

package com.soulboy;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

public class Main {
    public static void main(String[] args) {
        //指定驱动路径
        System.setProperty("webdriver.chrome.driver","C:\\Tools\\chromedriver-win64\\chromedriver.exe");
        // 谷歌驱动
        ChromeOptions options = new ChromeOptions();
        // 允许所有请求
        options.addArguments("--remote-allow-origins=*");
        WebDriver webDriver = new ChromeDriver(options);
        // 启动需要打开的网页
        webDriver.get("https://abc1024.tech");
    }
}

自动化测试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的元素,那么定位会失败。
package com.soulboy;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

import java.util.concurrent.TimeUnit;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        //指定驱动路径
        System.setProperty("webdriver.chrome.driver","C:\\Tools\\chromedriver-win64\\chromedriver.exe");
        // 谷歌驱动
        ChromeOptions options = new ChromeOptions();
        // 允许所有请求
        options.addArguments("--remote-allow-origins=*");
        WebDriver webDriver = new ChromeDriver(options);
        // 最大化浏览器
        webDriver.manage().window().maximize();

        //运行测试用例
        idTest(webDriver);
    }

    public static void idTest(WebDriver webDriver) throws InterruptedException {
        webDriver.get("https://xdclass.net");
        TimeUnit.SECONDS.sleep(4);
        // 利用id定位元素:输入框,并在输入框中输入:设计模式
        //sendKeys在对象上模拟按键输入内容
        webDriver.findElement(By.id("rc_select_0")).sendKeys("设计模式");
    }

}

Selenium4.X元素定位Name

  • Name元素定位
    • 在HTML中,某些元素(如<input>, <button>, <select>等)可以设置一个Name属性。
    • 虽然Name属性不必唯一,但在某些情况下,它可以用于定位特定的元素。
    • 在Selenium中,使用findElement(By.name(“name的值”));方法可以根据元素的Name属性进行定位
  • 注意事项​:
    • Name属性不必唯一,可能存在多个元素具有相同的Name,默认只会返回第一个匹配的元素。
    • 如果页面上的元素没有设置Name属性,或者Name属性的值发生了改变,那么定位会失败
  • 案例实操
package com.soulboy;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

import java.util.concurrent.TimeUnit;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        //指定驱动路径
        System.setProperty("webdriver.chrome.driver","C:\\Tools\\chromedriver-win64\\chromedriver.exe");
        // 谷歌驱动
        ChromeOptions options = new ChromeOptions();
        // 允许所有请求
        options.addArguments("--remote-allow-origins=*");
        WebDriver webDriver = new ChromeDriver(options);
        // 最大化浏览器
        webDriver.manage().window().maximize();

        //运行测试用例
        nameTest(webDriver);
    }
    public static void nameTest(WebDriver webDriver){
        webDriver.get("https://www.baidu.com");
        webDriver.findElement(By.name("wd")).sendKeys("周杰伦");
    }
}

Selenium4.X元素定位之linkText链接

Selenium4元素定位之链接方式

  • 通过超链接上的文字信息来定位元素,包括通过链接的全部文字和部分文字进行定位。
  • 链接的全部文字定位
    • 当链接的完整文本是唯一的,想要定位这个链接时,可以使用By.linkText方法
    • By.linkText("完整的链接文本")用于查找页面上文字完全匹配的链接。
    • 案例操作
public static void linkTest(WebDriver webDriver) throws InterruptedException {
        webDriver.get("https://xdclass.net");
        TimeUnit.SECONDS.sleep(2);
        //关闭广告
        webDriver.findElement(By.xpath("/html/body/div/div/div[2]/div/div/a/div/div/button/span")).click();
        TimeUnit.SECONDS.sleep(1);

        WebElement webElement = webDriver.findElement(By.linkText("课程中心"));
        String text = webElement.getText();
        System.out.println(text);
        //点击元素
        webElement.click();
    }

链接的部分文字定位

  • 当链接的文本不是唯一的,想基于部分文本来定位链接时,可以使用By.partialLinkText方法。
  • By.partialLinkText("部分链接文本")用于查找页面上文字包含指定文本的链接。
  • 案例操作
public static void partialLinkTest(WebDriver webDriver) throws InterruptedException {
        webDriver.get("https://xdclass.net");
        TimeUnit.SECONDS.sleep(3);
        //关闭广告
        webDriver.findElement(By.xpath("/html/body/div/div/div[2]/div/div/a/div/div/button/span")).click();
        TimeUnit.SECONDS.sleep(1);

        List<WebElement> webElements = webDriver.findElements(By.partialLinkText("课程"));
        System.out.println(webElements.size());

        WebElement firstElement = webElements.getFirst();
        System.out.println(firstElement);
        //点击元素
        firstElement.click();
    }
  • 注意事项

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

    Selenium4.X元素定位之Class

Selenium4元素定位之Class方式

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

HTML代码

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

语法代码

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

代码实战

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

输出

size=======26
会员特惠
手撕大厂算法-算法刷题大课训练营
级别:高级
12897
¥3199
¥2599
会员特惠
中间件项目大课-自动化云测平台/Spingboot3.X/微服务/Kafka3.x
级别:高级
13583
¥5799
¥5299
会员特惠
全栈多端低代码平台项目大课-系统化掌握React生态体系
级别:高级
12653
¥3599
¥2899
会员特惠
独孤求败-小滴云架构大课十八式-最强面试大课
级别:高级
31241
¥8999
¥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选择器定位元素案例说明

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

测试代码

public static void cssTest(WebDriver webDriver) throws InterruptedException {
        webDriver.get("https://xdclass.net");
        TimeUnit.SECONDS.sleep(3);
        //关闭广告
        webDriver.findElement(By.xpath("/html/body/div/div/div[2]/div/div/a/div/div/button/span")).click();
        TimeUnit.SECONDS.sleep(1);

        List<WebElement> elements = webDriver.findElements(By.cssSelector("div[class='title']"));
        System.out.println("size======="+elements.size());
        for (WebElement element : elements) {
            String text = element.getText();
            System.out.println(text);
        }
    }

输出

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

Selenium4.X元素定位之TagName

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

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

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

  • 注意事项

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

HTML源码

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

java代码

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

测试代码

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

输出结果

size = 63
-----javascript:void(0)
-----https://www.baidu.com/
-----javascript:;
-----https://passport.baidu.com/v2/?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2F&sms=5
新闻-----http://news.baidu.com/
hao123-----https://www.hao123.com/?src=from_pc
地图-----http://map.baidu.com/
贴吧-----http://tieba.baidu.com/
视频-----https://haokan.baidu.com/?sfrom=baidu-top
图片-----http://image.baidu.com/
网盘-----https://pan.baidu.com/?from=1026962h
文库-----https://wenku.baidu.com/?fr=bdpcindex
更多-----http://www.baidu.com/more/
-----http://fanyi.baidu.com/
-----http://xueshu.baidu.com/
-----https://baike.baidu.com/
-----https://zhidao.baidu.com/
-----https://jiankang.baidu.com/widescreen/home
-----http://e.baidu.com/ebaidu/home?refer=887
-----https://live.baidu.com/
-----http://music.taihe.com/
-----https://cp.baidu.com/?sa=bdindex
-----http://www.baidu.com/more/
登录-----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做元素定位的话, 脚本的执行速度可能会稍慢
        *

测试代码

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

输出结果

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

测试代码

public static void WebDriver(WebDriver webDriver) throws InterruptedException {
        //访问目标 url 地址,打开网页
        webDriver.get("https://www.baidu.com/");
        //getCurrentUrl() 方法获取当前页面的 url 地址
        String currentUrl = webDriver.getCurrentUrl();
        System.out.println("当前页面的 url 地址是:" + currentUrl);

        //getTitle() 方法获取当前页面的标题
        String title = webDriver.getTitle();
        System.out.println("当前页面的标题是:" + title);

        //getPageSource() 方法获取当前页面的源码
        String pageSource = webDriver.getPageSource();
        System.out.println("当前页面的源码是:" + pageSource);

        //close() 方法关闭当前页面
        //webDriver.close();

        //quit() 方法关闭所有浏览器
        //webDriver.quit();

        //通过 id 定位元素,并输入搜索关键词
        webDriver.findElement(By.id("kw")).sendKeys("小滴课堂");

        //findElements() 方法返回所有匹配的元素
        webDriver.findElements(By.id("kw")).get(0).sendKeys("小滴课堂");

        String windowHandle = webDriver.getWindowHandle();
        System.out.println("当前窗口句柄是:" + windowHandle);
/*        Set<String> windowHandles = webDriver.getWindowHandles();
        for (String windowHandle : windowHandles) {
            System.out.println("当前窗口句柄是:" + windowHandle);
        }*/
    }

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 更强调事件的独立性

测试代码

public static void webElementTest(WebDriver webDriver)throws InterruptedException {
        //启动需要打开的网页
        webDriver.get("https://www.baidu.com");
        String title = webDriver.getTitle();
        String currentUrl = webDriver.getCurrentUrl();
        System.out.println("title="+title+",currentUrl="+currentUrl);

        TimeUnit.SECONDS.sleep(2);

        //输入元素 sendKey
        webDriver.findElement(By.id("kw")).sendKeys("小滴课堂官网");
        TimeUnit.SECONDS.sleep(2);

        //清除元素  clear
        webDriver.findElement(By.id("kw")).clear();

        TimeUnit.SECONDS.sleep(2);
        webDriver.findElement(By.id("kw")).sendKeys("苹果手机");

        //点击元素  click
        webDriver.findElement(By.id("su")).click();
        TimeUnit.SECONDS.sleep(2);

        webDriver.findElement(By.id("kw")).clear();
        webDriver.findElement(By.id("kw")).sendKeys("苹果手机最新款");

        //提交元素  submit
        webDriver.findElement(By.id("su")).submit();
        String attributeValue = webDriver.findElement(By.id("su")).getAttribute("value");
        String attributeType = webDriver.findElement(By.id("su")).getAttribute("type");

        System.out.println("attributeValue======"+attributeValue);
        System.out.println("attributeType======"+attributeType);
    }

image.png

输出

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

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

  • 需求

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

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

代码分析

public static void browserTest(WebDriver webDriver)throws InterruptedException {
        //打开网页
        webDriver.get("https://www.baidu.com");
        //输入小滴课堂官网
        webDriver.findElement(By.id("kw")).sendKeys("小滴课堂官网");
        //点击搜索
        webDriver.findElement(By.id("su")).click();
        //浏览器刷新
        TimeUnit.SECONDS.sleep(2);
        webDriver.navigate().refresh();
        //浏览器后退一步
        TimeUnit.SECONDS.sleep(2);
        //加个休眠时间
        webDriver.navigate().back();

        //浏览器前进
        TimeUnit.SECONDS.sleep(2);
        webDriver.navigate().forward();
        TimeUnit.SECONDS.sleep(2);

        //浏览器窗口按照指定大小来显示
        webDriver.manage().window().setSize(new Dimension(300,300));
        TimeUnit.SECONDS.sleep(2);
        //浏览器全屏
        webDriver.manage().window().fullscreen();
    }

WebUI自动化操作之鼠标事件

  • Selenium的鼠标事件

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

    方法说明
    contextClick( )右击
    clickAndHold( )鼠标点击并控制
    doubleClick( )双击
    dragAndDrop( )拖动
    release( )释放鼠标
    perform( )执行所有Actions中存储的行为
    • 单击操作
WebElement element = driver.findElement(By.id("element_id")); // 替换为你要单击的元素的ID  
element.click(); // 或者使用 Actions 实现单击  
  
// 使用 ActionChains  
Actions actions = new Actions(driver);  
actions.click(element).perform();
  • 双击操作
WebElement element = driver.findElement(By.id("element_id")); // 替换为你要双击的元素的ID  
new Actions(driver).doubleClick(element).perform();
  • 右键操作
WebElement element = driver.findElement(By.id("element_id")); // 替换为你要右击的元素的ID  
new Actions(driver).contextClick(element).perform();
  • 悬停操作
WebElement element = driver.findElement(By.id("element_id")); // 替换为你要悬停的元素的ID  
new Actions(driver).moveToElement(element).perform();
  • 拖拽操作
WebElement sourceElement = driver.findElement(By.id("source_id")); // 源元素ID  
WebElement targetElement = driver.findElement(By.id("target_id")); // 目标元素ID  
new Actions(driver).dragAndDrop(sourceElement, targetElement).perform();
  • 测试代码
public static void mouseTest(WebDriver webDriver)throws InterruptedException{
        //打开网站
        webDriver.get("https://baidu.com");

        webDriver.findElement(By.cssSelector("#kw")).sendKeys("iphone100");

        //点击百度的搜索一下
        TimeUnit.SECONDS.sleep(2);
        webDriver.findElement(By.cssSelector("#su")).click();

        TimeUnit.SECONDS.sleep(2);
        WebElement element = webDriver.findElement(By.cssSelector("#s_tab > div > a.s-tab-item.s-tab-item_1CwH-.s-tab-wenku_GwhrW.s-tab-wenku"));

        //鼠标右键(文库)
        Actions actions = new Actions(webDriver);
        actions.moveToElement(element).contextClick().perform();
    }

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

什么是模拟键盘

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

发送特殊字符

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

模拟组合键操作

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

测试代码

public  static void  keyTest(WebDriver webDriver) throws InterruptedException {
        webDriver.get("https://www.baidu.com");

        // 定位到对应的元素
        WebElement input = webDriver.findElement(By.id("kw"));

        //输入框输入内容
        input.sendKeys("苹果手机教程");
        Thread.sleep(2000);

        //删除多输入的一个 程
        input.sendKeys(Keys.BACK_SPACE);
        Thread.sleep(2000);

        //输入空格键+“教程”
        input.sendKeys(Keys.SPACE);
        input.sendKeys("教程");
        Thread.sleep(2000);

        //通过回车键盘来代替点击操作
        input.sendKeys(Keys.ENTER);
        Thread.sleep(2000);
    }
  • 注意事项
    • 在发送键盘操作之前,请确保目标元素是可交互的(即可见且可点击)。
    • 如果元素在发送键盘操作之前处于隐藏或不可交互状态,可能会导致测试失败。
    • 在使用组合键时,请注意按键的顺序和释放的顺序,如果顺序不正确,可能会导致测试行为不符合预期。
  • 不同操作系统的键盘说明
windows:
send_keys(Keys.CONTROL, ‘a’) 方法用于全选文本,
send_keys(Keys.CONTROL, ‘c’) 方法用于复制文本,
send_keys(Keys.CONTROL, ‘x’) 方法用于剪切文本,
send_keys(Keys.CONTROL, ‘v’) 方法用于粘贴文本。
mac:
send_keys(Keys.COMMAND, ‘a’) 方法用于全选文本,
send_keys(Keys.COMMAND, ‘c’) 方法用于复制文本,
send_keys(Keys.COMMAND, ‘x’) 方法用于剪切文本,
send_keys(Keys.COMMAND, ‘v’) 方法用于粘贴文本。

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

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

代码示例

public static void waitTest(WebDriver webDriver)throws InterruptedException {
        //启动需要打开的网页
        webDriver.get("https://www.baidu.com");

        // 创建显式等待对象,设置最大等待时间为5秒,直到能搜索栏元素可以为止
        WebDriverWait wait = new WebDriverWait(webDriver, Duration.ofSeconds(5));
        // 使用ExpectedConditions定义等待条件,例如元素可见性
        wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("kw")));

        //隐式等待,可以用一个不存在的元素位置进行测试
        //webDriver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));
        //webDriver.findElement(By.id("kw1")).sendKeys("小滴课堂官网");

        //输入元素 sendKey
        webDriver.findElement(By.id("kw")).sendKeys("小滴课堂官网");

        //提交元素  submit
        webDriver.findElement(By.id("su")).submit();
        String text = webDriver.findElement(By.id("su")).getAttribute("value");
        System.out.println("text======"+text);
    }

Selenium4.X进阶难点攻克

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

代码示例

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

输出

currentHandle====3345B9414EBCE6583025396E0852923A
handle====3345B9414EBCE6583025396E0852923A
handle====C442F9AA2E373211A4D037230C6121C6

iframe实战自动登录126邮箱

什么是 iframe

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

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

  • 采用126邮箱站点进行测试
  • 注意:站点有动态id或者没有id和name等属性,可以用xpath或者css定位解决
public static void iframeTest(WebDriver webDriver) throws InterruptedException {
        webDriver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));
        //打开网站
        webDriver.get("https://www.126.com/");

        //需要切换到对应的iframe才可以
        WebElement element = webDriver.findElement(By.xpath("//div[@id='loginDiv']/iframe"));

        webDriver.switchTo().frame(element);

        //定位账号输入框(如果站点有动态id,则不能使用xpath)
        webDriver.findElement(By.xpath("//div[@class='u-input box']/input[@name='email']")).sendKeys("wcsb19900116");
        webDriver.findElement(By.xpath("//div[@class='u-input box']/input[@name='password']")).sendKeys("password123");

        //点击登录按钮
        WebElement dologin = webDriver.findElement(By.id("dologin"));
        System.out.println(dologin.getText());
        dologin.click();
    }

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

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

测试代码

public static void screenshotTest(WebDriver webDriver) throws IOException, InterruptedException {
        webDriver.get("https://baidu.com");
        webDriver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));
        webDriver.findElement(By.id("kw")).sendKeys("苹果手机1000");

        //点击搜索
        webDriver.findElement(By.cssSelector("#su")).click();
        //等待搜索结果加载完成后截图
        TimeUnit.SECONDS.sleep(1);

        //将快照文件存储,指定截图的保存路径和文件名,修改为你想要保存的路径和文件名
        File file = ((TakesScreenshot) webDriver).getScreenshotAs(OutputType.FILE);
        String screenshotPath = "D:\\screenshot\\screenshot.png";
        File target = new File(screenshotPath);
        // 保存截图到指定路径
        try (FileOutputStream out = new FileOutputStream(target)) {
            byte[] buffer = new byte[1024];
            FileInputStream fis = new FileInputStream(file);
            int bytesRead;
            while ((bytesRead = fis.read(buffer)) != -1) {
                out.write(buffer, 0, bytesRead);
            }
            fis.close();
        }
    }

screenshot.png

Selenium4.X下拉框Select处理

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

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

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

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

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

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

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

image.png

image.png

测试代码

public static void selectTest(WebDriver webDriver) throws InterruptedException {
        //直接把html文件用浏览器打开,然后复制地址栏这里打开
        //webDriver.get("file:///Users/xdclass/Desktop/select.html");

        //飞猫客网站
        webDriver.get("https://www.feimaoke.com");

        // 创建WebDriverWait对象,设置超时时长为10秒
        WebDriverWait wait = new WebDriverWait(webDriver, Duration.ofSeconds(10));
        wait.until(ExpectedConditions.elementToBeClickable(By.id("menu-item-116"))).click();

        // 移动光标(IT互联网)
        Actions actions = new Actions(webDriver);
        WebElement webElement = webDriver.findElement(By.id("menu-item-116"));
        actions.moveToElement(webElement).perform();
        TimeUnit.SECONDS.sleep(1);

        //下拉光标(SEO教程)
        WebElement webElement2 = webDriver.findElement(By.id("menu-item-117"));
        actions.moveToElement(webElement2).click().perform();


//        WebElement element = webDriver.findElement(By.id("mySelect"));
//        Select select = new Select(element);
//        List<WebElement> options = select.getOptions();
//        for (WebElement option : options) {
//            String text = option.getText();
//            System.out.println(text);
//        }
//
//        TimeUnit.SECONDS.sleep(2);
//        //根据选项的可见文本选择
//        select.selectByVisibleText("mysql");
//
//        TimeUnit.SECONDS.sleep(2);
//        //根据索引选择,从0开始
//        select.selectByIndex(1);
//
//        //根据value进行选择
//        TimeUnit.SECONDS.sleep(2);
//        select.selectByValue("4");
//
//        //判断是不是多选的选择框返回boolean值
//        System.out.println(select.isMultiple());
    }

Selenium4.X弹窗Alert处理

  • 什么是Alert

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

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

处理alert弹出框​:

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

处理confirm弹出框

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

测试代码

public static void alertTest(WebDriver webDriver) throws InterruptedException {
        //直接把html文件用浏览器打开,然后复制地址栏这里打开
        webDriver.get("file:///Users/xdclass/Desktop/select.html");

        // 创建WebDriverWait对象,设置超时时长为10秒
        WebDriverWait wait = new WebDriverWait(webDriver, Duration.ofSeconds(10));
        wait.until(ExpectedConditions.elementToBeClickable(By.id("alert_btn"))).click();
        //处理alert
        Alert alert = webDriver.switchTo().alert();
        System.out.println("getText()======"+alert.getText());
        TimeUnit.SECONDS.sleep(2);
        alert.accept();

        //处理confirm
        webDriver.findElement(By.id("confirm_btn")).click();
        Alert confirm = webDriver.switchTo().alert();
        TimeUnit.SECONDS.sleep(2);
        // 点击“确定”按钮
        confirm.accept();
        // 或者点击“取消”按钮
        //confirm.dismiss();
    }
  • 注意事项
    • 不是所有的浏览器和浏览器驱动都支持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
public static void cookieTest(WebDriver webDriver) throws Exception {
        webDriver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));
        webDriver.get("https://xdclass.net/");
        TimeUnit.SECONDS.sleep(3);
        //关闭弹窗
        webDriver.findElement(By.xpath("/html/body/div/div/div[2]/div/div/a/div/div/button/span")).click();
        TimeUnit.SECONDS.sleep(1);

        //出现登录窗口
        webDriver.findElement(By.xpath("/html/body/div/div/div[1]/div[2]/div[1]/div[2]/div/span[1]")).click();
        TimeUnit.SECONDS.sleep(2);
        //输入账号密码
        webDriver.findElement(By.id("form_item_account")).sendKeys("15221114839");
        webDriver.findElement(By.id("form_item_password")).sendKeys("xxxxx");
        TimeUnit.SECONDS.sleep(2);

        //点击立刻登录
        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();
        TimeUnit.SECONDS.sleep(2);

        Set<Cookie> cookies = webDriver.manage().getCookies();
        for (Cookie cookie : cookies) {
            System.out.println("Cookie Name: " + cookie.getName() +" Cookie Value: " + cookie.getValue());
        }
    }

输出

Cookie 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
    • 刷新当前页面
    • 进入课程中心
    • 进入商品详情页
    • 收藏商品
public static void loginTest(WebDriver webDriver) throws InterruptedException {
        //进入小滴课堂首页
        webDriver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));
        webDriver.get("https://xdclass.net/");
        TimeUnit.SECONDS.sleep(3);
        //关闭弹窗
        webDriver.findElement(By.xpath("/html/body/div/div/div[2]/div/div/a/div/div/button/span")).click();
        TimeUnit.SECONDS.sleep(2);

        //代码里面增加Cookie
        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";
        // 创建和设置Cookie
        Cookie authCookie = new Cookie.Builder("user", token)
                // 需要设置为您要登录的网站域名
                .domain("xdclass.net")
                // 通常是"/"
                .path("/")
                // 可以加其它属性,如 isHttpOnly, isSecure, expiry 等
                .build();

        //添加Cookie到当前的session
        webDriver.manage().addCookie(authCookie);

        //再次访问需要登录才能访问的页面,这时候应该已经“登录”了
        webDriver.navigate().refresh();
        TimeUnit.SECONDS.sleep(2);

        //关闭弹窗
//        webDriver.findElement(By.xpath("/html/body/div/div/div[2]/div/div/a/div/div/button/span")).click();
//        TimeUnit.SECONDS.sleep(1);

        //进入课程中心
        webDriver.findElement(By.xpath("/html/body/div[1]/div/div[1]/div[2]/div[1]/div[1]/a[2]")).click();
        TimeUnit.SECONDS.sleep(3);

        //获取全部窗口句柄
        Set<String> windowHandles = webDriver.getWindowHandles();
        String newHandle = "";
        for (String windowHandle : windowHandles) {
            //记录最后一个窗口的句柄
            newHandle = windowHandle;
            System.out.println(windowHandle);
        }

        //切换到课程中心 新窗口,没调用默认还是第一个窗口,则定位窗口的输入框元素会失败
        webDriver.switchTo().window(newHandle);
        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();
        TimeUnit.SECONDS.sleep(3);

        //切换课程详情页窗口
        String lastWindowHandle = webDriver.getWindowHandles().stream().reduce((first, second) -> second).orElse(null);
        webDriver.switchTo().window(lastWindowHandle);
        TimeUnit.SECONDS.sleep(3);

        //收藏课程
        webDriver.findElement(By.xpath("/html/body/div/div/div[2]/div/div[2]/div[1]/div[1]/div[4]/div[2]")).click();
    }

测试框架TestNG

  • 什么是TestNG框架

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

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

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

编写测试代码

package com.soulboy;

import org.testng.Assert;
import org.testng.annotations.Test;

public class testng {
    @Test
    public void verifySetup()
    {
        System.out.println("TestNG setup is working fine");
    }

    @Test
    public void testAssert() {
        System.out.println("这个是一个断言测试");
        int a = 9;
        int b = 100;
        Assert.assertTrue(a > b, "判断错误,出问题啦");
    }
}

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")​:指定使用哪个数据提供器。
@DataProvider(name = "testData")  
public Object[][] dpTest() {  
    return new Object[][] {  
        {1, "Lucy"},  
        {2, "Jack"}  
    };  
}  
  
@Test(dataProvider = "testData")  
public void testDataDriven(Integer id, String name) {  
    System.out.println("编号: " + id + ", 姓名: " + name);  
}

image.png

其他不常用的注解

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

TestNG作用域注解执行顺序

image.png

public class VerifyOrder {
    @Test
    public void testCase1() {
        System.out.println("这个是测试用例1执行");
    }

    @Test
    public void testCase2() {
        System.out.println("这个是测试用例2执行");
    }

    @BeforeMethod
    public void beforeMethod() {
        System.out.println("这个是beforeMethod执行");
    }

    @AfterMethod
    public void afterMethod() {
        System.out.println("这个是afterMethod执行");

    }

    @BeforeClass
    public void beforeClass() {
        System.out.println("这个是BeforeClass执行");

    }

    @AfterClass
    public void afterClass() {
        System.out.println("这个是afterClass执行");
    }

    @BeforeTest
    public void beforeTest() {
        System.out.println("这个是beforeTest执行");

    }

    @AfterTest
    public void afterTest() {
        System.out.println("这个是afterTest执行");
    }

    @BeforeSuite
    public void beforeSuite() {
        System.out.println("这个是beforeSuite执行");
    }

    @AfterSuite
    public void afterSuite() {
        System.out.println("这个是afterSuite执行");
    }

}

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

  • 默认执行顺序
    • 如果没有明确指定,TestNG默认会根据测试用例方法的名称进行排序和执行
    • 按照字典顺序(即字母和数字的顺序)来执行。
  • 使用@Test(priority=...)注解
    • @Test注解中,可以通过设置priority属性来指定测试用例的优先级。
    • 数值越小,优先级越高,即测试用例会先执行
    • 例如,@Test(priority=1)的测试用例会比@Test(priority=2)的测试用例先执行。
  • 使用dependsOnMethods属性
    • 通过在@Test注解中使用dependsOnMethods属性,可以指定一个或多个测试用例的依赖关系。
    • 一个测试用例的执行依赖于另一个或多个测试用例的执行结果。
    • 被依赖的测试用例会首先执行。例如:测试用例B会在测试用例A执行完毕后执行。
@Test  
public void testA() {  
    // 测试用例A的代码  
}  

@Test(dependsOnMethods = "testA")  
public void testB() {  
    // 测试用例B的代码,它依赖于testA的执行结果  
}
  • 注意事项
    • 当使用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

package com.soulboy;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

public class SeleniumBase {

    protected WebDriver webDriver;

    public void setUp() {
        //指定驱动路径
        System.setProperty("webdriver.chrome.driver","C:\\Tools\\chromedriver-win64\\chromedriver.exe");
        // 谷歌驱动
        ChromeOptions options = new ChromeOptions();
        // 允许所有请求
        options.addArguments("--remote-allow-origins=*");
        webDriver = new ChromeDriver(options);
        // 最大化浏览器
        webDriver.manage().window().maximize();
    }

    public void tearDown() {
        if (webDriver != null) {
            webDriver.quit();
        }
    }

    // 封装其他常用的方法,比如导航到URL、查找元素等
}

AssertMessage

package com.soulboy;

public class AssertMessage {
    public static final String ERROR_TITTLE_MESSAGE = "标题断言失败";
    public static final String ERROR_URL_MESSAGE = "URL断言失败";
    public static final String ERROR_CONTEXT_MESSAGE = "内容断言失败";
}

TestReadBookPage

package com.soulboy;

import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import java.time.Duration;
import java.util.concurrent.TimeUnit;

public class TestReadBookPage extends SeleniumBase {

    /**
     * 在所有测试执行前进行初始化操作。
     * 初始化浏览器驱动,设置隐式等待时间,并导航到豆瓣首页。
     */
    @BeforeClass
    public void setupClass() {
        setUp(); // 调用父类的初始化方法
        webDriver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
        webDriver.get("https://www.douban.com/");
    }

    /**
     * 在所有测试执行后进行清理操作。
     * 主要是为了调用父类的清理方法,确保资源正确释放。
     */
    @AfterClass
    public void tearDownClass() {
        tearDown(); // 调用父类的清理方法
    }

    /**
     * 测试豆瓣首页的标题是否包含"豆瓣"。
     * 该测试优先级为1,确保在其他测试之前执行。
     */
    @Test(priority = 1)
    public void testHomePageTitle() throws InterruptedException {
        String title = webDriver.getTitle();
        System.out.println("Title: " + title);
        //断言
        Assert.assertTrue(title.contains("豆瓣"), AssertMessage.ERROR_TITTLE_MESSAGE);
        TimeUnit.SECONDS.sleep(2);
    }

    /**
     * 首先点击进入读书页面,验证是否成功进入豆瓣读书页面
     * 该测试依赖于testHomePageTitle测试,只有在首页标题测试通过后才会执行。
     */
    @Test(priority = 2, dependsOnMethods = "testHomePageTitle")
    public void testEnterBook() throws InterruptedException {
        //点击读书
        webDriver.findElement(By.xpath("/html/body/div[1]/div[2]/div[1]/ul/li[1]/a")).click();

        //切换窗口
        webDriver.getWindowHandles().forEach(window -> webDriver.switchTo().window(window));
        String currentUrl = webDriver.getCurrentUrl();
        System.out.println("Current URL: " + currentUrl);
        Assert.assertTrue(currentUrl.contains("book.douban.com"), AssertMessage.ERROR_URL_MESSAGE);
        TimeUnit.SECONDS.sleep(2);
    }

    /**
     * 测试搜索功能,搜索关键词"java",验证是否进入搜索结果页面。
     * 该测试优先级为3,旨在测试搜索功能的基本可用性。
     */
    @Test(priority = 3)
    public void testSearchBook() throws InterruptedException {
        //获取搜索框input元素,并输入java
        webDriver.findElement(By.id("inp-query")).sendKeys("java");
        //点击submit按钮
        webDriver.findElement(By.xpath("/html/body/div[2]/div[1]/div/div[2]/form/fieldset/div[2]/input")).click();
        //断言(通过title是否包含java字段)
        String title = webDriver.getTitle();
        System.out.println("Title: " + title);
        TimeUnit.SECONDS.sleep(2);
        Assert.assertTrue(title.contains("java"),AssertMessage.ERROR_TITTLE_MESSAGE);

    }

    /**
     * 验证搜索结果中是否包含"Java核心技术·卷I"这本书。
     * 该测试依赖于testSearchPage,确保搜索功能正常后验证搜索结果。
     */
    @Test(priority = 4)
    public void testSearchResultCount() throws InterruptedException {
        //获取 Java核心技术·卷I(原书第12版) : 开发基础 元素
        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"));
        String text = element.getText();
        System.out.println(text);
        TimeUnit.SECONDS.sleep(2);
        //断言
        Assert.assertTrue(text.contains("Java核心技术·卷I"),AssertMessage.ERROR_CONTEXT_MESSAGE);

    }

    /**
     *  Java核心技术·卷I(原书第12版)
     * 该测试依赖于testSearchPage,确保搜索功能正常后验证搜索结果。
     */
    @Test(priority = 5)
    public void clickBookDetail() throws InterruptedException {
        //点击a链接,查看书籍详情
        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();
        TimeUnit.SECONDS.sleep(2);
        //断言
        Assert.assertTrue(webDriver.getTitle().contains("Java核心技术·卷I"),AssertMessage.ERROR_TITTLE_MESSAGE);

    }

}

作者:Soulboy