Selenium 介绍

Selenium 支持多平台、多浏览器、多语言去实现自动化测试,是一个开源和可移植的 Web 测试框架,支持并行测试执行,从而减少了时间并提高了测试效率。利用它,我们可以编写相关的自动化程序,让程序完全像人一样在浏览器里面操作 Web 界面,比如模拟鼠标点击、模拟键盘输入等等。不但能够操作 Web 界面,还能从 Web 中获取信息,并且相对来说,使用 Selenium 来获取信息更加简单,它的基本原理是我们编写自动化程序之后利用浏览器驱动直接对浏览器进行操作,只要我们用户能在浏览器上获得的信息使用 Selenium 都可以获得。

image.png

搭建 Selenium 环境

1、首先要求 Java 换件要在 1.8 版本之上

2、检查 Chrome 的版本,同时在 Google 驱动的官网上下载对应版本的驱动 https://googlechromelabs.github.io/chrome-for-testing/#canary

3、解压下载好的驱动压缩包,将下载好的c / hromedriver.exe放到java系统环境变量下

Selenium 使用

基本使用

1、首先在 IDEA 中创建测试类

image.png

2、在 maven 项目中引入 Selenium 框架

file:pom.xml
1
2
3
4
5
<dependency>
<groupld>org.seleniumhq.selenium</groupld>
<artifactld>selenium-java</artifactld>
<version>3.6.0</version>
</dependency>

3、创建 Chrome 驱动对象,要知道所有的 Selenium 操作都是通过驱动来完成的,所以我们首先需要获取谷歌驱动对象,下面三行代码是固定写法,记忆就好,理解起来也非常的简单

1
2
3
4
5
// 允许所有请求  
ChromeOptions chromeOptions = new ChromeOptions();
chromeOptions.addArguments("--remote-allow-origins=*");
// 创建一个驱动对象来打开浏览器
ChromeDriver chromeDriver = new ChromeDriver(chromeOptions);

4、get() 方法:获取到对应页面的地址,也就是获取一个URL。比如这里我们需要获取百度首页的地址

1
chromeDriver.get("https://www.baidu.com")

5、**元素定位方法 cssSelector():打开百度首页,鼠标右键,打开开发者工具,然后点击箭头,选中输入框,找到对应代码,然后鼠标右键,找到copy,点击 Copy selector;同时结合寻找元素方法 findElement()**,sendKeys()里面的内容就是输入框我们想输入的内容

1
chromeDriver.findElement(By.cssSelector("#kw").sendKeys("搜索的内容"));

6、**点击方法 click()**:定位到“百度一下”这个按钮需要使用我们的cssSelector方法,同时使用 click() 方法来进行点击操作

1
chromeDriver.findElement(By.cssSelector("#su")).click();

到此,一个完整的打开百度页面并且输入数据进行搜索的自动化代码就已经完成了,但是由于代码执行的速度非常快,我们看的不太清楚,可以使用 sleep() 来控制代码的执行速度,完整代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class firstAuto {  
public static void main(String[] args) throws InterruptedException {
// 允许所有请求
ChromeOptions chromeOptions = new ChromeOptions();
chromeOptions.addArguments("--remote-allow-origins=*");
// 创建一个驱动对象来打开浏览器
ChromeDriver chromeDriver = new ChromeDriver(chromeOptions);
// 输入百度地址
chromeDriver.get("https://www.baidu.com/");
sleep(3000);
chromeDriver.findElement(By.cssSelector("#kw")).sendKeys("selenium");
sleep(1000);
// 找到“百度一下”按钮并点击
chromeDriver.findElement(By.cssSelector("#su")).click();
sleep(1000);
// 释放驱动对象,关闭浏览器
chromeDriver.quit();
}
}

打印 URL 和 title

使用两个函数 getCurrentUrl() 和 getTitle(), 其返回值类型都是 String 类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class SecondAuto {  
public static void main(String[] args) {
ChromeOptions chromeOptions = new ChromeOptions();
chromeOptions.addArguments("--remote-allow-origins=");
ChromeDriver chromeDriver = new ChromeDriver(chromeOptions);
chromeDriver.get("https://www.baidu.com");

String currentUrl = chromeDriver.getCurrentUrl();
String title = chromeDriver.getTitle();
if (currentUrl.equals("https://www.baidu.com/") || title.equals("百度一下,你就知道")) {
System.out.println("测试通过,标题和url均正确。");
}
}
}

image.png

浏览器操作

可以使用 Selenium 设置浏览器的页面大小、浏览器前进与后退、刷新、滚动条滚动等操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class ThirdAuto {  
public static void main(String[] args) throws InterruptedException {
ChromeOptions chromeOptions = new ChromeOptions();
chromeOptions.addArguments("--remote-allow-origins=*");
ChromeDriver chromeDriver = new ChromeDriver(chromeOptions);
chromeDriver.get("https://www.baidu.com");

// 全屏
chromeDriver.manage().window().maximize();

// 设置固定宽、高
chromeDriver.manage().window().setSize(new Dimension(1000, 800));

chromeDriver.findElement(By.cssSelector("#kw")).sendKeys("apple");
chromeDriver.findElement(By.cssSelector("#su")).click();

// 浏览器回退
chromeDriver.navigate().back();
sleep(1000);
// 浏览器向前
chromeDriver.navigate().forward();
sleep(1000);
// 将浏览器滚动条拖到页面最底端 JS强制转换
((JavascriptExecutor) chromeDriver).executeScript("document.documentElement.scrollTop=10000");
}
}

键盘操作

这个操作是让自动化代码在运行过程中可以进行点击键盘上的按键操作:ctrl+a、ctrl+c、ctrl+v 等快捷键功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class FourthAuto {  
public static void main(String[] args) {
ChromeOptions options = new ChromeOptions();
options.addArguments("--remote-allow-origins=*");
ChromeDriver driver = new ChromeDriver(options);
driver.get("https://www.baidu.com/");

driver.manage().window().maximize();
driver.findElement(By.cssSelector("#kw")).sendKeys("apple");
driver.findElement(By.cssSelector("#kw")).sendKeys(Keys.CONTROL, "a");
driver.findElement(By.cssSelector("#kw")).sendKeys(Keys.CONTROL, "c");
driver.findElement(By.cssSelector("#kw")).sendKeys(Keys.CONTROL, "v");
driver.findElement(By.cssSelector("#su")).click();
}
}

鼠标事件

要使用鼠标事件需要导入工具包: import org.openqa.selenium.interactions.Actions;方法 move_to_element(element);移动鼠标到一个元素中,menu 上面已经定义了他所指向的哪一个元素;

  • 方法 perform() 执行所有存储的行为
  • contextClick() 右击
  • doubleClick() 双击
  • dragAndDrop() 拖动
  • moveToElement() 移动
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class FifthAuto {  
public static void main(String[] args) {
ChromeOptions options = new ChromeOptions();
options.addArguments("--remote-allow-origins=*");
ChromeDriver driver = new ChromeDriver(options);
driver.get("https://www.baidu.com/");

driver.findElement(By.cssSelector("#kw")).sendKeys("520");
driver.findElement(By.cssSelector("#su")).click();

//找到图片按钮
WebElement webElement = driver.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(driver);
actions.moveToElement(webElement).contextClick().perform();
}
}

定位一组元素

webdriver 可以很方便的使用 findElement 方法来定位某个特定的对象,不过有时候我们需要定位一组对象,这时候就需要使用 findElements 方法

定位一组对象通常用于以下场景:

  1. 批量操作对象,比如将页面上所有的 checkbox 都勾选上
  2. 先获取一组的对象,再在这组对象中过滤出需要具体定位的一些对象:比如定位页面上所有的 checkbox,然后选择最后一个

[!example] 具体演示

1、首先创建一个 html 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<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>

2、定位一组元素从而实现一次性勾选 checkbox1、2、3 这三个选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class SixthAuto {  
public static void main(String[] args) {
ChromeOptions options = new ChromeOptions();
options.addArguments("--remote-allow-origins=*");
ChromeDriver driver = new ChromeDriver(options);
driver.get("file:///C:/Users/Myth/Desktop/SixthAuto.html");

List<WebElement> webElements = driver.findElements(By.cssSelector("input"));
for (int i = 0; i < webElements.size(); i++) {
if (webElements.get(i).getAttribute("type").equals("checkbox")) {
webElements.get(i).click();
} else {

} }
}
}
  • 使用 Lisf<WebElement> 来存储所有带 input 标签的元素
  • 然后检查源代码,发现每个可以勾选的按钮都带有 type 属性
  • 那么就可以使用方法 getAttribute(“type”),括号中放的是数据类型,来定位到所有类型带type的元素;定位到之后进行click()点击操作

下拉框处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<html>
<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>

这里可以使用 Select 函数,创建一个 Select 对象,然后调用里面的方法;常见的使用下标定位或者通过 value 定位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class SeventhAuto {  
public static void main(String[] args) {
ChromeOptions options = new ChromeOptions();
options.addArguments("--remote-allow-origins=*");
ChromeDriver driver = new ChromeDriver(options);
driver.manage().window().maximize();
driver.get("file:///C:/Users/Myth/Desktop/SeventhAuto.html");

WebElement webElement = driver.findElement(By.cssSelector("#ShippingMethod"));
Select select = new Select(webElement);
select.selectByIndex(3);
select.selectByValue("9.03");
}
}

上传文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<html>  
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8"/>
<title>upload_file</title>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.min.js">
</script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css"
rel="stylesheet"/>
<script type="text/javascript">
</script>
</head>
<body>
<div class="row-fluid">
<div class="span6 well">
<h3>upload_file</h3>
<input type="file" name="file"/>
</div>
</div>
</body>
<script src="http://netdna.bootstrapcdn.com/twitterbootstrap/2.3.2/js/bootstrap.min.js"></script>
</html>

定位到上传文件按钮,然后输入想要上传文件的路径即可

1
2
3
4
5
6
7
8
9
10
public class EighthAuto {  
public static void main(String[] args) {
ChromeOptions options = new ChromeOptions();
options.addArguments("--remote-allow-origins=*");
ChromeDriver driver = new ChromeDriver(options);
driver.manage().window().maximize();
driver.get("file:///E:\\Code\\selenium_study\\src\\index\\EighthAuto.html");
driver.findElement(By.cssSelector("input")).sendKeys("E:\\Code\\selenium_study\\src\\index\\SeventhAuto.html");
}
}

quite 和 close 的区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class NinthAuto {  
public static void main(String[] args) throws InterruptedException {

ChromeOptions options = new ChromeOptions();
options.addArguments("--remote-allow-origins=*");
ChromeDriver driver = new ChromeDriver(options);
driver.manage().window().maximize();
driver.get("https://www.baidu.com");

// driver.findElement(By.cssSelector("#kw")).sendKeys("杨幂");
driver.findElement(By.cssSelector("#s-top-left > a:nth-child(1)")).click();
sleep(3000);
//quit是关闭整个浏览器
driver.quit();
//close只是关闭当前窗口
// driver.close();

//即quit会清空缓存,而close不会清空缓存。
}
}
  • close() 函数:上述代码打开了两个窗口句柄,随着代码的运行,关闭了一个窗口句柄
  • quit() 函数:上述代码打开了两个窗口句柄,随着代码的运行,直接关闭浏览器

浏览器页面跳转

那么我们在设计自动化代码的时候,可能会遇到页面从当前页面跳转到另一个新的页面,那么这个时候再去使用 cssSelector 或者 Xpath 方法去定位元素的话,肯定是定位不到的,因为跳转到了新的页面,get方法打开的是旧的页面,那么如何解决呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class TenthAuto {  
public static void main(String[] args) throws InterruptedException {
ChromeOptions options = new ChromeOptions();
options.addArguments("--remote-allow-origins=*");
ChromeDriver driver = new ChromeDriver(options);
driver.manage().window().maximize();
driver.get("https://www.baidu.com");

driver.findElement(By.cssSelector("#s-top-left > a:nth-child(1)")).click();
sleep(3000);

//通过getWindowHandles获取所有的窗口句柄
//通过getWindowHandle获取get打开的页面窗口句柄
Set<String> handles = driver.getWindowHandles();
//target用来获取当前最新的页面地址
String target = "";
for (String handle : handles) {
target = handle;
}
driver.switchTo().window(target);
driver.findElement(By.cssSelector("#ww")).sendKeys("新闻联播");
driver.findElement(By.cssSelector("#s_btn_wr")).click();
}
}

截图

这个操作会在指定页面进行截图并保存到对应的路径,在实际工作中与我们的预期进行对比

1、首先在 pom.xml 导入依赖

file:pom.xml
1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>

2、执行自动化代码,然后去目录路径中查看是否生成了对应的截图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class EleventhAuto {  
public static void main(String[] args) throws InterruptedException, IOException {
ChromeOptions options = new ChromeOptions();
options.addArguments("--remote-allow-origins=*");
ChromeDriver driver = new ChromeDriver(options);
driver.manage().window().maximize();
driver.get("https://www.baidu.com");

driver.findElement(By.cssSelector("#kw")).sendKeys("自动化测试");
driver.findElement(By.cssSelector("#su")).click();
sleep(3000);
File file = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(file, new File("E://demo10.png"));
}
}