Selenium学习(Java + Edge)

Selenium

/səˈliːniəm/

1. 简介

​ Selenium是一个用于Web应用程序自动化测试工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE、Mozilla Firefox、Safari、Google Chrome、Opera、Edge等。

​ 适用于自动化测试,js动态爬虫(破解反爬虫)等领域。

​ Selenium的核心Selenium Core基于JsUnit,完全由JavaScript编写,因此可以用于任何支持JavaScript的浏览器上。selenium可以模拟真实浏览器,自动化测试工具,支持多种浏览器。

Selenium官方

2. 组成

  • Selenium IDE:嵌入到Firefox浏览器中的一个插件,实现简单的浏览器操作录制与回放功能,主要用于快速创建BUG及重现脚本,可转化为多种语言;
  • Selenium RC: 核心组件,支持多种不同语言编写自动化测试脚本,通过其服务器作为代理服务器去访问应用,达到测试的目的;
  • Selenium WebDriver(重点):一个浏览器自动化框架,它接受命令并将它们发送到浏览器。它是通过特定于浏览器的驱动程序实现的。它直接与浏览器通信并对其进行控制。Selenium WebDriver支持各种编程语言,如Java、C# 、PHP、Python、Perl、Ruby;
  • Selenium grid:测试辅助工具,用于做分布式测试,可以并行执行多个测试任务,提升测试效率。

3. 特点

  1. 开源、免费
  2. 多浏览器支持:FireFox、Chrome、IE、Opera、Edge;
  3. 多平台支持:Linux、Windows、MAC;
  4. 多语言支持:Java、Python、Ruby、C#、JavaScript、C++;
  5. 对Web页面有良好的支持;
  6. 简单(API 简单)、灵活(用开发语言驱动);
  7. 支持分布式测试用例执行。

4. 配置

采用Java编写自动化测试代码。

4.1 环境依赖

注意:浏览器版本必须与Selenium驱动版本一致!
Edge:118.0.2088.76 x64

Selenium驱动:118.0.2088.76

Maven依赖:4.8.0

JDK:1.8.0_361

4.2 下载对应浏览器的驱动

注意:下载的驱动包需要与当前浏览器版本对对应。

4.4 配置驱动包

​ 将驱动包解压到jdk / bin目录下。

5. 运行

5.1 创建Maven项目


5.2 导入Selenium依赖

pom.xml

markdown 复制代码
<dependencies>
    <dependency>
        <groupId>org.seleniumhq.selenium</groupId>
        <artifactId>selenium-java</artifactId>
        <version>4.8.0</version>
    </dependency>

    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.6</version>
    </dependency>
</dependencies>

5.3 在test /java下创建类

或者直接在src -> main -> java下新建。

5.4 在自动化测试类中编写代码

java 复制代码
// 自动化测试类
public class AutoTest  {
    public void Test() throws InterruptedException, IOException {
        // Edge驱动
        EdgeOptions edgeOptions = new EdgeOptions();
        // 允许所有请求(允许浏览器通过远程服务器访问不同源的网页,即跨域访问)
        edgeOptions.addArguments("--remote-allow-origins=*");
        EdgeDriver edgeDriver = new EdgeDriver(edgeOptions);
        // 启动需要打开的网页
        edgeDriver.get("https://www.baidu.com");
        // 退出
        edgeDriver.quit();
    }
}
java 复制代码
import java.io.IOException;

// 启动类
public class RunAutoTest {
    public static void main(String[] args) throws InterruptedException, IOException {
        AutoTest autoTest = new AutoTest();
        autoTest.Test();
    }
}

5.5 启动

6. 使用

6.1 请求

方法 说明
driver.get(url) 请求一个页面,不支持前进和后退切换
driver.navigate().to(url) 和get类似,支持前进和后退切换
driver.navigate().forward(url) 指前进到下一个页面(必须后退一个页面后才能前进)
driver.navigate().back(url) 退到上一个页面(必须前进了一个页面才能回退)
driver.navigate().refresh(url) 刷新当前页面

6.2 定位元素

方法 描述
driver.findElement(By.id()) 使用元素的唯一标识ID进行定位
driver.findElement(By.name()) 使用元素的名称属性进行定位
driver.findElement(By.className()) 使用元素的类名进行定位
driver.findElement(By.tagName) 使用元素的标签名进行定位
driver.findElement(By.partialLinkText()) 使用链接文本进行定位
driver.findElement(By.cssSelector) 使用CSS选择器进行定位
driver.findElement(By.xpath) 使用XPath表达式进行定位

cssSelector:

cv工程


元素定位---cssSelector

  1. 根据tagName

    java 复制代码
    By.cssSelector("input");// 不推荐,tagName会重复
  2. 根据ID

    java 复制代码
    By.cssSelector("input#id");
    By.cssSelector("#id");
  3. 根据className(样式名)

    java 复制代码
    By.cssSelector(".className");
    By.cssSelector("input.className");

css精确定位

  1. 根据元素属性,属性名=属性值(id、calss等都可使用此形式)

    java 复制代码
    // By.cssSelector("标签名[属性名='属性值']");
    By.cssSelector("input[name='xxx']");
  2. 多属性

    java 复制代码
    By.cssSelector("标签名[属性名='属性值'][属性名='属性值']");

6.3 获取内容

方法 说明
String getPageSource() 获取页面html
String getTitle() 获取页面标题
String getText() 获取此元素(包括子元素)的可见(即未被CSS隐藏)文本
String getTagName() 获取此元素的标签名
String getAttribute(String name) 获取元素指定属性的值
Point getLocation() 获取当前元素,基于页面左上角的为准
Dimension getSize() 渲染元素的宽度和高度是多少
String getCurrentUrl() 获取表示浏览器正在查看的当前URL的字符串
String getCssValue(String propertyName) 获取指定元素的CSS属性的值

6.4 操作行为

方法 说明
clear() 如果该元素是文本输入元素,则会清除该值
submit() 提交from表单
click() 单击此元素
sendKeys() 使用此方法模拟在元素中键入,可以设置其值

注意:

有些页面是使用动态加载js的,会导致html页面正常显示,但js还没执行完毕,相关事件还没绑定到具体的元素上。导致出现操作无效或程序抛出异常。

可以在加载页面时强制等待,全部加载完毕后再进行后续操作。

6.5 窗口

方法 说明
driver.manage().window().setSize(new Dimension(1024, 768)) 设置当前窗口的大小
driver.manage().window().setPosition() 设置当前窗口的位置(相对于屏幕的左上角)
driver.manage().window().getSize() 获取当前窗口的大小
driver.manage().window().getPosition() 获取当前窗口相对于屏幕左上角的位置
driver.manage().window().fullScreen() 全屏当前窗口
driver.manage().window().maximize() 最大化当前窗口

6.6 切换指定窗口

​ 当浏览器每次打开一个标签页的时候,会自动的给一个标签进行标识,这个标识我们称之为"句柄"。

方法 说明
String getWindowHandle() 返回当前窗口句柄,通过将其传递给switchTo(),进行切换窗口
driver.switchTo().window(windowHandle) 切换到指定句柄的窗口
java 复制代码
    String curHandle = edgeDriver.getWindowHandle();// 获取当前页面句柄
    System.out.println("当前句柄:" + curHandle);
    Set<String> handles = edgeDriver.getWindowHandles();// 获取所有页面句柄
    for (String handle : handles) {
        if (!handle.equals(curHandle)) {// 发生页面切换
            edgeDriver.switchTo().window(handle);// 切换窗口
        }
    }

6.7 iframe切换

方法 说明
driver.switchTo().frame(index) 根据index进行切换
driver.switchTo().frame(id) 根据id进行切换
driver.switchTo().frame(name) 根据name进行切换
driver.switchTo().frame(WebElement) 根据WebElement进行切换
driver.switchTo().defaultContent() 切换后,回到默认内容页面(否则会找不到元素)

6.8 模拟键盘和鼠标

6.8.1 键盘事件
方法 说明
driver.findElement(By.id("kw")).sendKeys(Keys.CONTROL, "a") ctrl+a
driver.findElement(By.id("kw")).sendKeys(Keys.CONTROL, "c") ctrl+c
driver.findElement(By.id("kw")).sendKeys(Keys.CONTROL, "v") ctrl+v
driver.findElement(By.id("kw")).sendKeys(Keys.TAB) TAB键
driver.findElement(By.id("kw")).sendKeys(Keys.ENTER) 回车键
driver.findElement(By.id("kw")).sendKeys(Keys.SPACE) 空格键
6.8.2 鼠标事件
java 复制代码
Actions actions = new Actions(driver);
方法 说明
actions.contextClick(element).perform() 右键点击enement的元素
actions.clickAndHold(element).perform() 左键单击enement元素
actions.doubleClick(element).perform() 鼠标左键双击enement元素
actions.moveToElement(element).perform() 鼠标悬停enement元素(中间)
actions.moveToElement(element,x,y).perform() 鼠标悬停enement元素(指定位置)
actions.moveToElement(x,y).perform(); 将鼠标从其当前位置移动鼠标
Actions dragAndDrop(WebElement source, WebElement target) 拖动元素, 在源元素的位置执行点击并保持,移动到目标元素的位置,然后释放鼠标
Actions dragAndDropBy(WebElement source, int xOffset, int yOffset) 拖动到指定位置 拖动到指定位置

6.9 等待

6.9.1 强制等待
java 复制代码
    Thread.sleep(millisecond);

程序阻塞执行,不建议。

6.9.2 显式等待

​ 显式等待是添加到代码中的循环,在应用程序退出循环并继续执行代码中的下一个命令之前,它会轮询应用程序以查找特定条件以评估为true。如果在指定的超时值之前未满足条件,则代码将给出超时错误。

java 复制代码
WebElement revealed = driver.findElement(By.id("revealed"));
Wait<WebDriver> wait = new WebDriverWait(driver, Duration.ofSeconds(2));

driver.findElement(By.id("reveal")).click();
wait.until(d -> revealed.isDisplayed());

revealed.sendKeys("Displayed");
6.9.3 隐式等待

​ 这是一个全局设置,适用于整个会话的每个元素位置调用。默认值为0,这意味着如果找不到元素,它将立即返回错误。如果设置了隐式等待,则在返回错误之前,驱动程序将等待所提供值的持续时间。请注意,一旦找到元素,驱动程序将返回元素引用,代码将继续执行,因此较大的隐式等待值不一定会增加会话的持续时间。

java 复制代码
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(2));

注意:

​ 不要混合隐式和显式等待。这样做可能会导致不可预测的等待时间。

​ 例如,设置10秒的隐式等待和15秒的显式等待可能会导致20秒后发生超时。

6.10 弹窗

  1. 警告弹窗中, 切换到弹窗,调用 accept()
  2. 确认弹窗中, 切换到弹窗,调用 accept() 或者 dismiss()
  3. 提示弹窗中, 切换到弹窗, 可以先输入文本, 调用 sendKeys(), 然后调用 accept() 或者 dismiss().
    提示:这里的 sendKeys() 在页面上看不到输入文本的执行效果
java 复制代码
driver.get("...");
Thread.sleep(3000);

// 打开弹窗
driver.findElement(By.cssSelector("body > input[type=button]")).click();
Thread.sleep(3000);

// 切换到弹窗进行弹窗的处理
Alert alert = driver.switchTo().alert();
Thread.sleep(3000);

// 弹窗输入文本
alert.sendKeys("abcdef");

// 点击确认
alert.accept();

// 点击取消
// alert.dismiss();

driver.quit();
6.10.1 警告弹窗

警告弹窗中, 切换到弹窗,调用 accept()

6.10.2 确认弹窗

确认弹窗中, 切换到弹窗,调用 accept() 或者 dismiss()

6.10.3 提示弹窗

提示弹窗中, 切换到弹窗, 可以先输入文本, 调用 sendKeys(), 然后调用 accept() 或者 dismiss().

提示:这里的 sendKeys() 在页面上看不到输入文本的执行效果

6.11 下拉选择框

方法 说明
select.getOptions() 获取所有选项
select.selectByIndex(index) 根据索引选中对应的元素
select.selectByValue(value) 选择指定value值对应的选项
select.selectByVisibleText(text) 选中文本值对应的选项
html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
<select name="ss" id="sss">
    <option value="12.5">**12.5**</option>
    <option value="6.6">**6.6**</option>
    <option value="486.4">**486.4**</option>
    <option value="21.12">**21.12**</option>
    <option value="99.99">**99.99**</option>
</select>
</body>
</html>
java 复制代码
package org.example;

import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.edge.EdgeDriver;
import org.openqa.selenium.edge.EdgeOptions;
import org.openqa.selenium.support.ui.Select;

import java.time.Duration;

public class Main {
    public static void main(String[] args) throws Exception {
        EdgeOptions edgeOptions = new EdgeOptions();
        edgeOptions.addArguments("--remote-allow-origins=*");
        EdgeDriver edgeDriver = new EdgeDriver(edgeOptions);
        edgeDriver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));// 隐式等待

        edgeDriver.get("file:///D:/idea-workspace/WebTest/src/main/resources/web/fileUpload/select.html");

//        WebElement webElement = edgeDriver.findElement(By.cssSelector("sss"));
//        Select select = new Select(webElement);
        Select select = new Select(edgeDriver.findElement(By.cssSelector("#sss")));

        // 根据文本选择
        Thread.sleep(3000);
        select.selectByVisibleText("**99.99**");

        // 根据索引值选择
        Thread.sleep(3000);
        select.selectByIndex(1);

        // 根据属性值选择
        Thread.sleep(3000);
        select.selectByValue("6.6");

        Thread.sleep(1000);
        edgeDriver.quit();
    }
}
6.11.1 根据文本选择
java 复制代码
WebElement webElement = driver.findElement(By.cssSelector("#Method"));

// 创建选择框对象(将此web元素封装为Select对象)
Select select = new Select(webElement)

// 根据文本来选择
select.selectByVisibleText("选择框文本");

Thread.sleep(3000);
driver.quit();
6.11.2 根据属性值选择
java 复制代码
WebElement webElement = driver.findElement(By.cssSelector("#Method"));

// 创建选择框对象(将此web元素封装为Select对象)
Select select = new Select(webElement)

// 根据属性值来选择
select.selectByValue("选择框属性值");

Thread.sleep(3000);
driver.quit();
6.11.3 根据序号选择

注意:select下拉框索引值从0开始!

java 复制代码
WebElement webElement = driver.findElement(By.cssSelector("#Method"));

// 创建选择框对象(将此web元素封装为Select对象)
Select select = new Select(webElement)

// 根据序号来选择
select.selectByIndex(1);

Thread.sleep(3000);
driver.quit();

6.12 文件上传

java 复制代码
public void fileUploadController() throws InterruptedException {
	driver.get("");
	Thread.sleep(3000);
	
	driver.findElement(By.cssSelector("body > div > div > input[type=file]")).sendKeys("文件路径");
	Thread.sleep(3000);
	driver.quit();
}

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
<input type="file" id="fu" value="选择文件">
<br>
<input type="button" id="fw" value="上传">
</body>
</html>

java 复制代码
package org.example;

import org.openqa.selenium.By;
import org.openqa.selenium.edge.EdgeDriver;
import org.openqa.selenium.edge.EdgeOptions;

import java.time.Duration;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("Hello world!");
        EdgeOptions edgeOptions = new EdgeOptions();
        edgeOptions.addArguments("--remote-allow-origins=*");
        EdgeDriver edgeDriver = new EdgeDriver(edgeOptions);
        edgeDriver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));// 隐式等待

        edgeDriver.get("file:///D:/idea-workspace/WebTest/src/main/resources/web/fileUpload/fileUpload.html");
        Thread.sleep(3000);

        edgeDriver.findElement(By.cssSelector("#fu")).sendKeys("D:/idea-workspace/WebTest/src/main/resources/web/fileUpload/fileUpload.html");

        Thread.sleep(3000);
        edgeDriver.quit();

    }
}


注意:如果上传文件前端控件源码不是input类型,需要使用第三方工具,比如:autoit

6.13 时间日期控件

  • 控件没有限制手动输入,则直接调用sendKeys方法写入时间数据。
  • 控件有限制输入,则可以通过执行一段js脚本来改变元素的value属性值。
6.13.1 方式一
java 复制代码
package org.example;

import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.edge.EdgeDriver;
import org.openqa.selenium.edge.EdgeOptions;
import org.openqa.selenium.support.ui.Select;

import java.time.Duration;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        EdgeOptions edgeOptions = new EdgeOptions();
        edgeOptions.addArguments("--remote-allow-origins=*");
        EdgeDriver edgeDriver = new EdgeDriver(edgeOptions);
        edgeDriver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));// 隐式等待

        edgeDriver.get("https://www.fliggy.com/?ttid=seo.000000580&seoType=origin");
        edgeDriver.findElement(By.cssSelector("#J_FlightForm > fieldset > div:nth-child(5) > div > div > input")).sendKeys("2000-01-01");

        Thread.sleep(1000);
        edgeDriver.quit();
    }
}
6.13.2 方式二
	见 6.13 执行脚本

6.13 执行脚本

方法 说明
driver.executeScript() 参数为要执行的js脚本
java 复制代码
package org.example;

import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.edge.EdgeDriver;
import org.openqa.selenium.edge.EdgeOptions;
import org.openqa.selenium.support.ui.Select;

import java.time.Duration;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        EdgeOptions edgeOptions = new EdgeOptions();
        edgeOptions.addArguments("--remote-allow-origins=*");
        EdgeDriver edgeDriver = new EdgeDriver(edgeOptions);
        edgeDriver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));// 隐式等待

        edgeDriver.get("https://www.12306.cn/index/");
//        edgeDriver.findElement(By.id("train_date"));
//        edgeDriver.executeScript("var v = train_date;\n" + "v.autocomplete = true");
        edgeDriver.executeScript("var v = train_date; v.autocomplete = true");
        edgeDriver.findElement(By.id("train_date")).clear();
        edgeDriver.findElement(By.id("train_date")).sendKeys("2000-01-01");

        Thread.sleep(1000);
        edgeDriver.quit();
    }
}

6.14 浏览器参数设置

java 复制代码
EdgeOptions edgeOptions = new EdgeOptions();
edgeOptions.addArguments("--remote-allow-origins=*");
addArguments可接收参数 说明
"--disable-gpu" 禁用GPU加速
"--headless" 在无头模式下运行浏览器,即不显示图形界面
"--incognito" 在隐身模式下启动浏览器
"--disable-extensions" 禁用浏览器扩展
"--disable-notifications" 禁用浏览器通知
"--disable-popup-blocking" 禁用弹出窗口拦截功能
"--start-maximized" 启动时最大化浏览器
"--disable-infobars" 禁用信息栏(例如Chrome正在受到自动测试软件控制)
"--ignore-certificate-errors" 忽略证书错误
"--proxy-server=http://hostname:port" 设置代理服务器

注意:浏览器的参数设置需要在创建浏览器对象之前进行设置。

6.15 验证码

6.15.1 万能验证码(推荐)

​ 后端代码添加测试通用验证码。

6.15.2 去除验证码

​ 后端去除验证码。

6.15.3 自动识别(难度大)

​ 可以付费调用自动识别API,不推荐。

6.16 退出

方法 说明
driver.close() 关闭当前窗口(如果是当前打开的最后一个窗口,则退出浏览器)
driver.quit() 退出此驱动程序,关闭每个相关窗口

在操作完毕后必须调用quit()进行释放资源,否则驱动将持续在内存中不会被释放掉。

7. 最后

码字不易,xdm,qiuqiu点个👍吧!

相关推荐
陈大爷(有低保)22 分钟前
UDP Socket聊天室(Java)
java·网络协议·udp
kinlon.liu36 分钟前
零信任安全架构--持续验证
java·安全·安全架构·mfa·持续验证
李小星同志37 分钟前
高级算法设计与分析 学习笔记6 B树
笔记·学习
霜晨月c1 小时前
MFC 使用细节
笔记·学习·mfc
王哲晓1 小时前
Linux通过yum安装Docker
java·linux·docker
java6666688881 小时前
如何在Java中实现高效的对象映射:Dozer与MapStruct的比较与优化
java·开发语言
Violet永存1 小时前
源码分析:LinkedList
java·开发语言
小江湖19941 小时前
元数据保护者,Caesium压缩不丢重要信息
运维·学习·软件需求·改行学it
执键行天涯1 小时前
【经验帖】JAVA中同方法,两次调用Mybatis,一次更新,一次查询,同一事务,第一次修改对第二次的可见性如何
java·数据库·mybatis
Jarlen1 小时前
将本地离线Jar包上传到Maven远程私库上,供项目编译使用
java·maven·jar