Selenium之路: UI自动化测试的必备指南
一. 什么是自动化测试
自动化测试指软件测试的自动化,可以使用软件工具或脚本来执行测试任务的过程,以替代人工进行重复性、繁琐或耗时的测试活动;是将人为驱动的测试行为转化为机器执行的过程 。
自动化测试包括 UI 自动化,接口自动化,单元测试自动化。
二. selenium的介绍
1. Selenium是什么
Selenium 是 Web 应用中基于 UI 的自动化测试框架,它的优点如下:
- 开源免费。
- 支持多浏览器,比如 Chrome,Edge,Firefox,Safari 等。
- 支持多语言,包括 Java,Python,C# 等,都可以使用 Selenium 这个工具。
- 支持多操作系统,比如 Windows,Linux,Mac 等。
- Selenium 的底层封装了丰富的 API,可以直接拿来使用。
2. Selenium的工作原理
🍂用 Selenium 实现自动化,主要需要三个东西:
- 自动化测试代码:自动化测试代码发送请求给浏览器的驱动。
- 浏览器驱动:它来解析这些自动化测试的代码,解析后把它们发送给浏览器。
- 浏览器:执行浏览器驱动发来的指令,并最终完成工程师想要的操作。
🍂Selenium 脚本执行时后端实现的流程:
- 对于编写的每一条 Selenium 脚本测试代码,都会创建一个 Http 请求并且发送给浏览器的驱动。
- 浏览器驱动中包含了一个 HTTP Server,用来接收这些 Http 请求。
- HTTP Server 接收到请求后,浏览器驱动程序会将请求解析成浏览器可以识别的命令并发送给浏览器。
- 浏览器执行接收到的命令,例如导航至指定 URL、查找和操作页面上的元素等。
- 浏览器将执行结果返回给 HTTP Server。
- HTTP Server 又将结果返回给 Selenium 的脚本,以便进行进一步的处理和验证。
3. Selenium 的环境搭建
我这里演示的是使用 Java + Selenium 来进行自动化测试的教程,使用的 JDK 的是 1.8 版本,JDK 1.8 可以兼容 Selenium 2.x、3.x 和 4.x 版本,浏览器使用的是 Chrome。
1️⃣第一步,查看自己 Chrome 浏览器的版本。
2️⃣第二步,点击下面链接下载相应版本浏览器驱动。
ChromeDriver - WebDriver for Chrome - Downloads (chromium.org)
找版本前三位数一样的,最后一位如果找不到一样的就找一个最接近的。
3️⃣第三步,解压下载好的驱动压缩包,将下载好的 chromedriver.exe 放到 java 系统环境变量下(我这里是C:\Program Files\Java\jdk1.8.0_192\bin
) 。
4️⃣第四步,打开 IDEA,创建一个 Maven 项目:在 pom.xml 文件中添加以下依赖,添加后记得 reload。
<dependencies>
<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.59</version>
</dependency>
</dependencies>
5️⃣第五步,验证环境是否搭建成功,创建一个类验证下面的代码是否可以运行。
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) {
ChromeOptions options = new ChromeOptions();
// 允许所有请求
options.addArguments("--remote-allow-origins=*");
//创建一个驱动对象来打开浏览器
WebDriver webDriver = new ChromeDriver();
// 打开百度首页
webDriver.get("https://www.baidu.com");
}
}
如果出现以下内容,则说明 Selenium 环境搭建已经成功。
上述代码的含义如下:
ChromeOptions options = new ChromeOptions();
// 允许所有请求
options.addArguments("--remote-allow-origins=*");
// 创建一个驱动对象来打开浏览器
WebDriver webDriver = new ChromeDriver();
前两行代码是为了解决跨域问题,第三行代码是在创建 Chrome 驱动对象,要知道所有的 Selenium 操作都是通过驱动来完成的,所以我们首先需要获取谷歌驱动对象,这三行代码是固定写法。
// 打开百度首页
webDriver.get("https://www.baidu.com");
get() 方法就是获取到对应页面的地址打开页面,也就是获取一个 URL,比如这里就是获取百度首页的地址并打开页面。
此时环境搭建就已经完毕了,接下来介绍 Selenium 的常见 API。
三. webdriver API
1. 元素的定位
假如要测试一个百度网页,输入一个 “Test” ,是否返回 Test 相关数据;此时我们需要找到百度的输入框在哪里,然后输入相关信息,再去找百度一下这个按钮在哪里,然后去点击它,那么代码的测试也是一样的,首先要做的就是定位元素,再进行一些操作。
定位一个元素最常用的是CSS
定位和XPath
定位,通过这两种定位方式几乎可以找到页面几乎所有的元素,但 CSS 选择器定位元素的方式更高效。
1.1 CSS 定位
在 Web 页面中可以通过以下方式找到 CSS 定位,以百度页面为例,首先打开百度首页,鼠标右键,点检查,打开开发者工具,然后点击箭头,选中输入框,找到对应代码,然后鼠标右键,找到copy
,点击Copy selector
即可。
有了定位就可以配合元素定位方法cssSelector()
和寻找元素的方法findElement()
使用,sendKeys()
里面的内容就是输入框我们想输入的内容;
driver.findElement(By.cssSelector("#kw")).sendKeys("软件测试");
♨️测试案例:实现一个自动化操作,在百度框输入“软件测试”,点击“百度一下”按钮进行搜索。
此时在上面的基础上我们还需要定位到“百度一下”这个按钮,同时使用click()
方法来进行点击操作,代码如下:
private static void test() {
// 创建一个选项
ChromeOptions options = new ChromeOptions();
// 设置参数为允许所有请求
options.addArguments("--remote-allow-origins=*");
// 创建浏览器驱动, 传入选项
WebDriver webDriver = new ChromeDriver(options);
// 打开百度首页
webDriver.get("https://www.baidu.com");
// 找到百度搜索输入框
webDriver.findElement(By.cssSelector("#kw")).sendKeys("软件测试");
//找到“百度一下”按钮,并点击
webDriver.findElement(By.cssSelector("#su")).click();
}
public static void main(String[] args) throws InterruptedException {
test();
}
执行结果:
🎯下面列出几种常见的 CSS 选择器:
- 标签选择器:通过标签名称来选择对应的元素。语法形式为 “标签名称”,例如 “div” 表示选择所有的 div 元素。
- 类选择器:通过元素的 class 属性值来选择对应的元素。语法形式为 “.class值” ,例如 “.myClass” 表示选择 class 属性值为 “myClass” 的所有元素。
- id 选择器:通过元素的 id 属性值来选择对应的元素。语法形式为 “#id值”,例如 “#myElement” 表示选择 id 属性值为 “myElement” 的元素
- 属性选择器:通过元素的属性和属性值来选择对应的元素。语法形式为 “[属性=‘属性值’]”,例如 “[href=‘https://example.com’]” 表示选择 href 属性值为 “https://example.com” 的所有元素。
- 伪类选择器:通过元素的特定状态或位置来选择对应的元素。常见的伪类选择器包括 :hover(鼠标悬停)、:first-child(第一个子元素)、:last-child(最后一个子元素)等。
1.2 XPath 定位
类似的也可以找到 XPath 定位,鼠标右键,点检查,打开开发者工具,然后点击箭头,选中输入框,找到对应代码,然后鼠标右键,找到copy
,点击Copy XPath(相对路径)/Copy full Xpath(绝对路径)
即可。
同样配合元素定位方法By.xpath()
和寻找元素的方法findElement()
使用即可。
WebElement element = webDriver.findElement(By.xpath("//*[@id=\"kw\"]"));
这个就不做冗余的演示了.
🎯这里主要介绍几种常用的 XPath 选择语法:
1️⃣绝对路径:/html/head/title (不常用)
2️⃣相对路径:
- 相对路径+索引(找下标):
//form/span[1]/input
,表示在 form 标签下/选中第二个 span 标签/找到 input 标签。 - 相对路径+属性值(找相关属性):
//input[@class="s_ipt"]
,表示选取 input 元素中 class 属性值为 s_ipt 的标签。 - 相对路径+通配符:
//*[@*="s_ipt"]
,表示找到任意属性值为的 s_ipt 的任意标签。 - 相对路径+文本匹配:
//a[text()="新闻"]
,表示选择文本内容为"新闻"的所有标签。
更多详细的语法可以参考在线教程:w3school 在线教程
1.3 实现一个自动化需求
♨️自动化需求:实现一个在百度的输入框中输入”软件测试“,是否返回对应的数据。
private static void test01() throws InterruptedException {
// 创建一个选项
ChromeOptions options = new ChromeOptions();
// 设置参数为允许所有请求
options.addArguments("--remote-allow-origins=*");
// 创建浏览器驱动, 传入选项
WebDriver webDriver = new ChromeDriver(options);
// 打开百度首页
webDriver.get("https://www.baidu.com");
// 找到百度搜索输入框
WebElement element = webDriver.findElement(By.xpath("//*[@id=\"kw\"]"));
// 输入软件测试
element.sendKeys("软件测试");
// 找到搜索按钮, 并进行点击
webDriver.findElement(By.cssSelector("#su")).click();// 这里也可以使用 submit
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.HOURS);
// 校验搜索出来的结果是不是和软件测试相关的内容
List<WebElement> elements = webDriver.findElements(By.cssSelector("a em"));
int flag = 0;
for (WebElement e : elements) {
if (e.getText().contains("软件测试")) {
flag = 1;
System.out.println("测试通过!");
break;
}
}
if (flag == 0) {
System.out.println("测试不通过!");
}
}
public static void main(String[] args) throws InterruptedException {
test01();
}
测试结果:
2. 操作测试对象
上面主要介绍了元素的定位,但是定位只是第一步,定位之后需要对元素素进行操作,是鼠标点击还是键盘输入,或者清除元素的内容,或者提交表单等。
webdriver 中比较常用的操作对象的方法有下面几个:
操作 | 说明 |
---|---|
click | 点击对象 |
send_keys | 在对象上模拟按键输入 |
clear | 清除对象输入的文本内容 |
submit | 提交 |
text | 用于获取元素的文本信息 |
getAttribute | 获取元素对应属性的值 |
2.1 clear 清除对象输入的文本内容
♨️自动化需求:打开一个百度的首页,并且在输入框中输入“测试开发”,并且点击“百度一下”按钮,最后清除输入框内容。
private static void test02() throws InterruptedException {
ChromeOptions options = new ChromeOptions();
options.addArguments("--remote-allow-origins=*");
WebDriver webDriver = new ChromeDriver(options);
webDriver.get("https://www.baidu.com/");
// 找到百度搜索输入框并输入 "测试开发"
webDriver.findElement(By.cssSelector("#kw")).sendKeys("测试开发");
// 找到搜索按钮, 并进行点击
webDriver.findElement(By.cssSelector("#su")).click();
// 等待3秒
sleep(3000);
// 清空百度搜索输入框中的数据
webDriver.findElement(By.cssSelector("#kw")).clear();
}
public static void main(String[] args) throws InterruptedException {
test02();
}
测试结果:
2.2 submit 提交
这个需要注意的是,如果点击的元素是放在 form 标签中的,此时使用 submit 实现的效果和 click 是一样的;如果点击的元素是放在非 form 标签中,此时使用 submit 会报错。
♨️测试案例:点击百度中的“新闻”超链接,这个超链接没有放在 form 标签中,则会报错。
private static void test03() {
ChromeOptions options = new ChromeOptions();
options.addArguments("--remote-allow-origins=*");
WebDriver webDriver = new ChromeDriver(options);
webDriver.get("https://www.baidu.com/");
// 注意这里不能使用 submit, submit 的使用要求标签元素必须在 from 表单内
webDriver.findElement(By.xpath("//a[text()=\"新闻\"]")).submit();
}
public static void main(String[] args) throws InterruptedException {
test03();
}
报错了:
2.3 getAttribute 获取元素对应属性的值
♨️自动化需求:找到“百度一下”按钮,验证这个按钮 value 属性值是不是“百度一下”,这个值不是放在标签中间,不可以通过 test 来获取,这个时候需要通过 getAttribute 获取元素对应属性的值。
private static void test04() {
ChromeOptions options = new ChromeOptions();
options.addArguments("--remote-allow-origins=*");
WebDriver webDriver = new ChromeDriver(options);
webDriver.get("https://www.baidu.com/");
// getAttribute获取标签内的属性值, 获取搜索按钮中的 value 属性的值
String button_value = webDriver.findElement(By.cssSelector("#su")).getAttribute("value");
if(button_value.equals("百度一下")) {
System.out.println("测试通过!");
} else {
System.out.println(button_value);
System.out.println("测试不通过!");
}
}
public static void main(String[] args) throws InterruptedException {
test04();
}
测试结果:
3. 添加等待
等待方式可以分为两大类:
- 强制等待:sleep(),这个平时也很常用,就不做过多的介绍了。
- 智能等待:隐式等待,显示等待。
🎯隐式等待和显示等待的区别如下:
- 显示等待和隐式等待都可以设置一个时间范围,在范围内不断寻找元素,超时找不到就会抛出异常。
- 可以把隐式等待当做全局变量,它影响整个页面,所以程序需要等待整个页面加载完成,才会执行下一步;隐式等待对整个 WebDriver 的周期都起作用,所以只要设置一次即可。
- 相比隐式等待,显式等待可以将它看成是局部变量,它只对指定元素生效,不再是在整个 WebDriver 生命周期内生效,可以根据需要定位的元素来设置显式等待,无需等待页面完全加载。
- 隐式等待是自动等待的,不需要在代码中显式调用,而显示等待需要在代码中显式调用等待方法。
3.1 隐式等待
隐式等待可以通过添加implicitlyWait()
方法就可以方便的实现智能等待,implicitlyWait() 的用法比 sleep() 更智能,后者只能选择一个固定的时间的等待,前者可以在一个时间范围内智能的等待。
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.DAYS);
隐式地等待并非一个固定的等待时间,当脚本执行所需要的元素都被定位到时,时间没到也会则继续执行后续的代码;如果还有元素定位不到,则它以轮询的方式不断的判断元素是否被定位到,直到超出设置的时长。
♨️测试案例:这里假设等待 3 天时间,设置隐式等待最长等待为 3 天,如果 3 天内获取到页面上的元素,此时执行下边的代码;如果等待 3 天时间还是没有找到这个元素,此会报错。
private static void test02() throws InterruptedException {
ChromeOptions options = new ChromeOptions();
options.addArguments("--remote-allow-origins=*");
WebDriver webDriver = new ChromeDriver(options);
webDriver.get("https://www.baidu.com/");
// 找到百度搜索输入框并输入 "测试开发"
webDriver.findElement(By.cssSelector("#kw")).sendKeys("测试开发");
// 找到搜索按钮, 并进行点击
webDriver.findElement(By.cssSelector("#su")).click();
// 等待3秒后再清空
// sleep(3000);
// 隐式等待, 收集到后面代码所需要的所有元素就会停止等待
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.DAYS);
// 清空百度搜索输入框中的数据
webDriver.findElement(By.cssSelector("#kw")).clear();
}
public static void main(String[] args) throws InterruptedException {
test02();
}
执行结果:
3.2 显式等待
显式等待与隐式不同,它是等待的是一定的条件,比如等待某个元素可以被被点击,等待元素可见。
♨️这里设置等待条件为,等待页面标题是否为"百度一下,你就知道"。
private static void test05() {
// 创建驱动
WebDriver webDriver = new ChromeDriver();
// 打开百度首页
webDriver.get("https://www.baidu.com/");
// 判断元素是否可以被点击
WebDriverWait wait = new WebDriverWait(webDriver, 1);
wait.until(ExpectedConditions.titleIs("百度一下,你就知道"));
}
public static void main(String[] args) throws InterruptedException {
test05();
}
执行结果:
4. 打印信息
♨️比如要检验百度首页的 url 和 title 是否符合预期,这里主要会用到了两个函数 getCurrentUrl() 和 getTitle(),它们的返回值类型是 String,所以可以定义两个 String 变量来接收。
private static void test06() {
ChromeOptions options = new ChromeOptions();
options.addArguments("--remote-allow-origins=*");
WebDriver webDriver = new ChromeDriver(options);
webDriver.get("https://www.baidu.com/");
String url = webDriver.getCurrentUrl();
String title = webDriver.getTitle();
if(url.equals("https://www.baidu.com/") && title.equals("百度一下,你就知道")) {
System.out.println("当前页面url: " + url + ", 当前页面title: " + title);
System.out.println("测试通过!");
} else {
System.out.println("测试不通过!");
}
}
public static void main(String[] args) throws InterruptedException {
test06();
}
测试结果:
5. 浏览器的操作
浏览器的操作包括设置浏览器的页面大小,浏览器前进,后退,刷新,滚动条滑动等。
操作 | 说明 |
---|---|
webDriver.manage().window().maximize(); | 浏览器的最大化 |
webDriver.manage().window().setSize(new Dimension(width, high)); | 设置浏览器宽、高 |
webDriver.navigate().forward(); | 浏览器的前进 |
webDriver.navigate().back(); | 浏览器的后退 |
webDriver.navigate().refresh(); | 浏览器的刷新 |
document.documentElement.scrollTop=0 | 将浏览器滚动条滑到最顶端 |
document.documentElement.scrollTop=10000 | 将浏览器滚动条滑到最底端 |
♨️测试案例:先打开一个浏览器,继续打开百度网页,然后让浏览器最大化,接着再让浏览器变为固定的宽和高,让后搜索“白鹿”并且百度一下,进行浏览器回退、浏览器刷新、浏览器前进,再将滚动条滑动最底端,再到最顶部。
浏览器滚动条的控制需要依靠 js 脚本。
private static void test07() throws InterruptedException {
ChromeOptions options = new ChromeOptions();
options.addArguments("--remote-allow-origins=*");
ChromeDriver driver = new ChromeDriver(options);
driver.get("https://www.baidu.com/");
// 最大化
driver.manage().window().maximize();
sleep(1000);
// 设置固定宽,高
driver.manage().window().setSize(new Dimension(1000,800));
driver.findElement(By.cssSelector("#kw")).sendKeys("白鹿");
driver.findElement(By.cssSelector("#su")).click();
sleep(2000);
// 浏览器回退
driver.navigate().back();
sleep(2000);
// 浏览器刷新
driver.navigate().refresh();
sleep(2000);
// 浏览器前进
driver.navigate().forward();
sleep(2000);
// 将浏览器滚动条滑到最底端 JS脚本强制转换
((JavascriptExecutor)driver).executeScript("document.documentElement.scrollTop=10000");
sleep(2000);
// 将浏览器滚动条滑到最顶端
((JavascriptExecutor)driver).executeScript("document.documentElement.scrollTop=0");
}
public static void main(String[] args) throws InterruptedException {
test07();
}
测试结果:
6. 键盘事件
这个操作是让自动化代码在运行过程中可以进行点击键盘上的按键操作,可以通过 send_keys() 方法和 Keys 类的常量来模拟键盘操作。
操作 | 说明 |
---|---|
send_keys(Keys.TAB) | # TAB |
send_keys(Keys.ENTER) | # 回车 |
send_keys(Keys.SPACE) | #空格键 |
send_keys(Keys.ESCAPE) | #回退键(Esc) |
send_keys(Keys.CONTROL,‘a’) | #全选(Ctrl+A) |
send_keys(Keys.CONTROL,‘c’) | #复制(Ctrl+C) |
send_keys(Keys.CONTROL,‘x’) | #剪贴(Ctrl+X) |
send_keys(Keys.CONTROL,‘v’) | #粘贴(Ctrl+V) |
例如:
private static void test08() throws InterruptedException {
WebDriver webDriver = new ChromeDriver();
webDriver.get("https://www.baidu.com/");
webDriver.findElement(By.cssSelector("#kw")).sendKeys("白鹿");
sleep(3000);
//ctrl+A
webDriver.findElement(By.cssSelector("#kw")).sendKeys(Keys.CONTROL, "A");
sleep(3000);
//ctrl+X
webDriver.findElement(By.cssSelector("#kw")).sendKeys(Keys.CONTROL, "X");
//ctrl+V
sleep(3000);
webDriver.findElement(By.cssSelector("#kw")).sendKeys(Keys.CONTROL, "V");
}
public static void main(String[] args) throws InterruptedException {
test08();
}
执行结果:
7. 鼠标事件
要使用鼠标事件需要导入工具包:
import org.openqa.selenium.interactions.Actions;
语法:
#鼠标拖动事件
Actions(webDriver).moveToElement(webElement).contextClick().perform();
Actions(webDriver):生成用户的行为。
moveToElement(element):移动鼠标到一个元素上。
perform():执行所有存储的行为。
常用鼠标事件如下:
操作 | 说明 |
---|---|
contextClick() | 右击 |
doubleClick() | 双击 |
dragAndDrop() | 拖动 |
dragAndDrop() | 移动 |
♨️测试案例:打开百度首页,搜索“520”并且百度一下,把鼠标放在图片的按钮上进行右击。
private static void test09() throws InterruptedException {
WebDriver webDriver = new ChromeDriver();
webDriver.get("https://www.baidu.com/");
webDriver.findElement(By.cssSelector("#kw")).sendKeys("520");
webDriver.findElement(By.cssSelector("#su")).click();
sleep(3000);
// 找到图片按钮
WebElement webElement = webDriver.findElement(By.cssSelector("#s_tab > div > a.s-tab-item.s-tab-item_1CwH-.s-tab-pic_p4Uej.s-tab-pic"));
// 鼠标右击出现框
Actions actions = new Actions(webDriver);
sleep(2000);
//contextClick()右击鼠标
actions.moveToElement(webElement).contextClick().perform();
}
public static void main(String[] args) throws InterruptedException {
test09();
}
执行结果:
7. 定位一组元素
webdriver 可以很方便的使用findElement
方法来定位某个特定的对象,不过有时候我们却需要定位一组对象,这时候就需要使用findElements
方法。
定位一组对象一般用于以下场景:
- 批量操作对象,比如将页面上所有的
checkbox
都勾上。 - 先获取一组对象,再在这组对象中过滤出需要具体定位的一些对象。比如定位出页面上所有的checkbox,然后选择最后一个。
有以下页面:
用浏览器打开这个如下页面我们看到三个复选框和两个单选框。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Checkbox</title>
</head>
<body>
<h3>checkbox</h3>
<div class="well">
<form class="form-horizontal">
<div class="control-group">
<label class="control-label" for="c1">checkbox1</label>
<div class="controls">
<input type="checkbox" id="c1" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="c2">checkbox2</label>
<div class="controls">
<input type="checkbox" id="c2" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="c3">checkbox3</label>
<div class="controls">
<input type="checkbox" id="c3" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="r">radio</label>
<div class="controls">
<input type="radio" id="r1" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="r">radio</label>
<div class="controls">
<input type="radio" id="r2" />
</div>
</div>
</form>
</div>
</body>
</html>
♨️下面我们就来定位这三个复选框,然后将这三个checkbox
都勾上。
private static void page01() {
WebDriver webDriver = new ChromeDriver();
webDriver.get("http://localhost:63342/_20230925testcode/src/main/Page/test01.html?_ijt=hk3glm0bcb2222roak6kf4826i&_ij_reload=RELOAD_ON_SAVE");
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.DAYS);
List<WebElement> webElements = webDriver.findElements(By.cssSelector("input"));
for(int i = 0; i < webElements.size(); i++) {
// 如果每个元素type值等于checkbox进行点击
// getAttribute获取页面上的元素属性值,里面的type是当前元素属性
if(webElements.get(i).getAttribute("type").equals("checkbox")){
webElements.get(i).click();
} else {
// 否则什么也不操作
;
}
}
}
public static void main(String[] args) throws InterruptedException {
page01();
}
这个代码使用 List 来存储所有是 input 标签的元素,其中每个可以勾选的按钮都带有 type 属性,那么就可以使用方法 getAttribute(“type”) 来定位到一些指定元素,定位到之后进行 click() 点击操作即可。
执行结果:
8. 多层框架/窗口定位
对于一个web应用,经常会出现框架(yrame或)窗口(window)的应用,这也就给我们的定位带来了一定的困难。
- 定位一个frame :
switchTo.frame(name or id or frameElement)
,通过 frame 的 id 或者 name 或者 frame 自带的其它属性来定位框架,这里switchTo.frame()
把当前定位的主体切换了frame
里。 switchTo.defaultContent
:从 frame 中嵌入的页面里跳出,跳回到最外面的默认页面中。- 定位一个窗口window:
switchTo.window(name_or_id_or_frame_element)
有以下页面:
frame.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>frame</title>
<!-- <link href="https://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" />-->
<script type="text/javascript">$(document).ready(function(){
});
</script>
</head>
<body>
<div class="row-fluid">
<div class="span10 well">
<h3>frame</h3>
<iframe id="f1" src="inner.html" width="800", height="600"></iframe>
</div>
</div>
</body>
<!--<script src="https://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>-->
</html>
inner.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>inner</title>
</head>
<body>
<div class="row-fluid">
<div class="span6 well">
<h3>inner</h3>
<iframe id="f2" src="https://www.baidu.com/"
width="700"height="500"></iframe>
<a href="javascript:alert('watir-webdriver better than selenium webdriver;')">click</a>
</div>
</div>
</body>
</html>
♨️这里我们要定位到页面中 click 这个弹窗元素。
要注意不可以直接用 webDriver.findElement(By.cssSelector(" ")).click();,此时这个页面中 frame 里边的元素是获取不到的。
正确的做法是先通过 switchTo.frame() 方法将定位到指定框架,再通过一般方式定位框架中的元素。
private static void page02() {
WebDriver webDriver = new ChromeDriver();
webDriver.get("http://localhost:63342/T-20230515/src/main/Page/test02.html");
webDriver.switchTo().frame("f1");
webDriver.findElement(By.cssSelector("body > div > div > a")).click();
}
public static void main(String[] args) throws InterruptedException {
page02();
}
执行结果:
9. 下拉框处理
下拉框是我们最常见的一种页面元素,对于一般的元素,我们只需要一次就定位,但下拉框里的内容需要进行两次定位,先定位到下拉框select
,再定位到下拉框内里的选项option
。
这里主要会用到一个 Select 方法,使用先要创建一个 Select 对象,然后去调用里面对应的方法,常见的使用下标定位(Index,从0开始)或者通过 Value 来进行定位。
有以下界面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>select</title>
</head>
<body>
<select id="ShippingMethod" onchange="updateShipping(options[selectedIndex]);" name="ShippingMethod">
<option value="12.51">UPS Next Day Air ==> $12.51</option>
<option value="11.61">UPS Next Day Air Saver ==> $11.61</option>
<option value="10.69">UPS 3 Day Select ==> $10.69</option>
<option value="9.03">UPS 2nd Day Air ==> $9.03</option>
<option value="8.34">UPS Ground ==> $8.34</option>
<option value="9.25">USPS Priority Mail Insured ==> $9.25</option>
<option value="7.45">USPS Priority Mail ==> $7.45</option>
<option value="3.20" selected="">USPS First Class ==> $3.20</option>
</select>
</body>
</html>
♨️我们分别用下标定位第 4 个元素,用 值 Value 值 定位第一个元素。
代码实现:
private static void page03() {
WebDriver webDriver = new ChromeDriver();
webDriver.get("http://localhost:63342/T-20230515/src/main/Page/test03.html");
WebElement webElement = webDriver.findElement(By.cssSelector("#ShippingMethod"));
Select select = new Select(webElement);
// 通过下标来选择
// select.selectByIndex(3);
// 通过value值来选择
select.selectByValue("12.51");
}
public static void main(String[] args) throws InterruptedException {
page03();
}
执行结果:
10. alert弹窗的处理
通过 switchTo.alert() 处理原生的 alert 弹窗。
操作 | 说明 |
---|---|
webDriver.switchTo().alert().text() | 返回 alert 中的文字信息 |
webDriver.switchTo().alert().accept() | 点击确认按钮 |
webDriver.switchTo().alert().dismiss() | 点击取消按钮 |
webDriver.switchTo().alert().sendKeys(“输入的值”) | 输入值,如果 alert 没有对话框就不能用了,不然会报错 |
有以下页面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>title</title>
</head>
<body>
<button onclick="Click()">这是一个弹窗</button>
</body>
<script type="text/javascript">
function Click() {
let name = prompt("请输入姓名:");
let parent = document.querySelector("body");
let child = document.createElement("div");
child.innerHTML = name;
parent.appendChild(child)
}
</script>
</html>
♨️测试案例:代码编写一个 alert 弹窗,在弹窗中输入"韵秋梧桐",随后 alert 弹窗确认。
private static void page04() throws InterruptedException {
WebDriver webDriver = new ChromeDriver();
webDriver.get("http://localhost:63342/T-20230515/src/main/Page/test04.html");
webDriver.findElement(By.cssSelector("button")).click();
sleep(3000);
// alert弹窗取消
webDriver.switchTo().alert().dismiss();
sleep(3000);
// 点击按钮
webDriver.findElement(By.cssSelector("button")).click();
// 在alert弹窗中输入"韵秋梧桐"
webDriver.switchTo().alert().sendKeys("韵秋梧桐");
// alert弹窗确认
sleep(3000);
webDriver.switchTo().alert().accept();
}
public static void main(String[] args) throws InterruptedException {
page04();
}
执行结果:
11. 上传文件操作
手动的上传操作一般要打开一个本地窗口,从窗口选择本地文件添加。
而这里只需要要定位上传按钮,通过 sendKeys() 添加本地文件路径就可以了,绝对路径和相对路径都可以,关键是上传的文件存在。
有如下页面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>upload_file上传文件</title>
</head>
<body>
<input type="file">
</body>
</html>
♨️测试案例:实现一个上传文件需求
private static void page05() {
WebDriver webDriver = new ChromeDriver();
webDriver.get("http://localhost:63342/T-20230515/src/main/Page/test05.html");
webDriver.findElement(By.cssSelector("input")).sendKeys("D:\\img\\cat1.jpg");
}
public static void main(String[] args) throws InterruptedException {
page05();
}
测试结果:
12. 关闭浏览器
关闭操作分为两种:
- quit() :关闭整个浏览器,并且清空缓存。
- close() :只是关闭原始窗口(源页面),不会清空缓存。
♨️测试案例:打开百度首页,点击新闻按钮,通过 quit 和 click 方法关闭浏览器。
private static void test10() throws InterruptedException {
WebDriver webDriver = new ChromeDriver();
webDriver.get("https://www.baidu.com/");
// 找到新闻按钮并点击
webDriver.findElement(By.cssSelector("#s-top-left > a:nth-child(1)")).click();
sleep(2000);
webDriver.quit();
// webDriver.close();
}
public static void main(String[] args) throws InterruptedException {
test10();
}
使用 quit 执行结果:
使用 close 执行结果:
13. 切换窗口
我们在设计自动化代码的时候,可能会遇到页面从当前页面跳转到另一个新的页面,那么这个时候再直接去使用 cssSelector 或者 Xpath 方法去定位元素的话,肯定是定位不到的,因为跳转到了新的页面,get 方法打开的是旧的页面,比如当我们从百度页面打开新闻页面的时候,此时我们如果想要在新闻页面操作百度一下,那么就得切换窗口。
此时我们可以使用getWindowHandles()
获取全部的窗口句柄(getWindowHandle 是获取 get 打开的页面窗口句柄),遍历存储全部句柄的Set
获取到我们需要的最后一个句柄,然后就通过webDriver.switchTo().window()
来切换窗口了。
♨️测试案例:打开百度首页,点击新闻按钮,在百度新闻框输入“新闻联播”并且点击百度一下
private static void test11() throws InterruptedException {
WebDriver webDriver = new ChromeDriver();
webDriver.get("https://www.baidu.com/");
// 找到新闻按钮并点击
webDriver.findElement(By.cssSelector("#s-top-left > a:nth-child(1)")).click();
sleep(1000);
// 通过getWindowHandles获取所有的窗口句柄
// 通过getWindowHandle获取的get打开的页面窗口句柄
System.out.println(webDriver.getWindowHandle());
Set<String> handles = webDriver.getWindowHandles();
String target_handle = "";
for(String handle:handles) {
target_handle = handle;
}
webDriver.switchTo().window(target_handle);
sleep(3000);
// 在输入框中搜索新闻联播
webDriver.findElement(By.cssSelector("#ww")).sendKeys("新闻联播");
// 点击"百度一下"
webDriver.findElement(By.cssSelector("#s_btn_wr")).click();
}
执行结果:
14. 截图
这个操作的话就是会在指定的页面进行截图,然后保存到对应的路径,在实际工作中对比与我们的预期结果是否一致。
首先需要在我们的配置文件pom.xml中导入依赖;
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
截图操作:((TakesScreenshot)webDriver).getScreenshotAs(OutputType.FILE);
复制到硬盘:FileUtils.copyFile(File srcFile, File destFile);
♨️测试案例:打开百度首页,输入“软件测试”,对测试页面进行截图
private static void test12() throws InterruptedException, IOException {
WebDriver webDriver = new ChromeDriver();
webDriver.get("https://www.baidu.com/");
webDriver.findElement(By.cssSelector("#kw")).sendKeys("软件测试");
webDriver.findElement(By.cssSelector("#su")).click();
sleep(3000);
// 强转成截图对象
File file = ((TakesScreenshot)webDriver).getScreenshotAs(OutputType.FILE);
// 将截图好的图片存储到D:\img\jietu01.png路径下
FileUtils.copyFile(file, new File("D:\\img\\jietu01.png"));
}
public static void main(String[] args) throws InterruptedException, IOException {
test12();
}
测试结果:
截图已经保存到了指定路径