Java+Selenium+TestNG+Allure
一、创建maven项目二、安装selenium1、引入selenium2、引入WebDriver2.1 手动引入2.2 自动下载2.3 完整代码
三、引入依赖四、编写自动化脚本五、元素的定位5.1、通过id查找元素5.2、通过class查找元素5.3、通过name查找元素5.4、通过cssSelector来查找元素5.5、通过XPATH来查找元素
六、常用测试方法6.1 操作元素6.2 获取内容6.3 页面请求6.4 窗口6.4.1 获取百度首页句柄以及新闻页面句柄6.4.2 切换句柄6.4.3 设置窗口大小
6.5 等待6.5.1 强制等待6.5.2 隐式等待6.5.3 显式等待
6.6 弹窗6.7 文件上传6.7.1文件操作工具类示例
6.8 关闭和退出6.9 代理配置工具类示例6.10 随机用户代理工具类示例6.11 截图并保存为文件
一、创建maven项目

二、安装selenium
1、引入selenium
通过下载jar包,或者通过maven引入。
这里使用 maven 管理项目依赖,所以在pom.xml添加以下依赖:
<!-- Selenium WebDriver Java -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.0</version>
</dependency>
2、引入WebDriver
想用selenium驱动不同的浏览器需要不同的浏览器驱动,这里将会使用Chrome浏览器进行自动化测试,所以需要下载 ChromeDriver ,需要下载与目标浏览器相匹配的版本号的驱动器(不过Chrome浏览器一般都会自动更新,所以直接下载最新版的驱动器就是了)。
2.1 手动引入
手动下载地址: https://chromedriver.chromium.org/downloads
历史版本 Chrome:https://www.slimjet.com/chrome/google-chrome-old-version.php

logger.info("使用已下载的 ChromeDriver");
try {
// 设置系统属性,指定chromedriver的路径
// 从配置文件中读取 ChromeDriver 路径
String driverPath = ConfigUtils.getString("webdriver.chrome");
logger.info("ChromeDriver 路径设置为: {}" , driverPath);
System.setProperty("webdriver.chrome.driver", driverPath);
} catch (Exception e) {
logger.error("设置 ChromeDriver 路径失败: {}" , e.getMessage());
throw new RuntimeException("设置 ChromeDriver 路径失败: " + e.getMessage());
}
2.2 自动下载
webdriver驱动管理依赖,只要引入依赖.就不要我们手动的去处理浏览器版本的问题。
只需要我们在pom.xml文件中引入依赖,每次使用都会帮助我们下载新的驱动
<!-- webdrivermanager 依赖 自动检测本地浏览器版本,并从官方源下载匹配的驱动程序,无需人工干预 -->
<dependency>
<groupId>io.github.bonigarcia</groupId>
<artifactId>webdrivermanager</artifactId>
<version>5.8.0</version>
</dependency>
logger.info("自动下载 ChromeDriver");
WebDriverManager.chromedriver().setup();
2.3 完整代码
logger.info("初始化driver");
// 判断是否启动自动下载
if (ConfigUtils.getBoolean("webdriver.autodriver")) {
logger.info("自动下载 ChromeDriver");
WebDriverManager.chromedriver().setup();
} else {
logger.info("使用已下载的 ChromeDriver");
try {
// 从配置文件中读取 ChromeDriver 路径
String driverPath = ConfigUtils.getString("webdriver.chrome");
logger.info("ChromeDriver 路径设置为: {}" , driverPath);
System.setProperty("webdriver.chrome.driver", driverPath);
} catch (Exception e) {
logger.error("设置 ChromeDriver 路径失败: {}" , e.getMessage());
throw new RuntimeException("设置 ChromeDriver 路径失败: " + e.getMessage());
}
}
三、引入依赖
<properties>
<!-- 依赖版本 -->
<selenium.version>3.141.0</selenium.version>
<webdrivermanager.version>5.8.0</webdrivermanager.version>
<testng.version>7.8.0</testng.version>
<allure.version>2.13.2</allure.version>
<aspectj.version>1.9.20</aspectj.version>
<slf4j.version>2.0.9</slf4j.version>
<jetbrains-annotations.version>24.0.1</jetbrains-annotations.version>
<!-- 插件版本 -->
<maven-compiler-plugin.version>3.11.0</maven-compiler-plugin.version>
<maven-surefire-plugin.version>3.1.2</maven-surefire-plugin.version>
<allure-maven.version>2.10.0</allure-maven.version>
<maven-assembly-plugin.version>3.6.0</maven-assembly-plugin.version>
</properties>
<dependencies>
<!-- Selenium WebDriver Java -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>${selenium.version}</version>
</dependency>
<!-- webdrivermanager 依赖
自动检测本地浏览器版本,并从官方源下载匹配的驱动程序,无需人工干预
用途: 自动管理 WebDriver 的二进制文件,简化驱动配置过程。
使用方式:
在初始化 WebDriver 前调用 WebDriverManager.chromedriver().setup(); 等方法自动设置驱动。
-->
<dependency>
<groupId>io.github.bonigarcia</groupId>
<artifactId>webdrivermanager</artifactId>
<version>${webdrivermanager.version}</version>
</dependency>
<!-- TestNG 测试框架-->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>${testng.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.testng</groupId>
<artifactId>testng-old</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Allure TestNG 集成 -->
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-testng</artifactId>
<version>${allure.version}</version>
<scope>test</scope>
</dependency>
<!-- AspectJ Weaver 供面向切面编程(AOP)的能力,常用于 Allure 测试报告生成。 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
<!-- JetBrains Annotations 提供静态分析注解,帮助提高代码质量 -->
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>${jetbrains-annotations.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Allure Maven 报告插件 -->
<plugin>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-maven</artifactId>
<version>${allure-maven.version}</version>
<configuration>
<reportVersion>${allure.version}</reportVersion>
</configuration>
</plugin>
<!-- Surefire 插件:执行 TestNG 测试 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<!-- 测试失败后,是否忽略并继续测试 -->
<testFailureIgnore>false</testFailureIgnore>
<!--设置参数命令行 -->
<argLine>
<!-- 用于解决TestNG Result中文乱码 -->
-Dfile.encoding=UTF-8
<!-- 配置拦截器 -->
-javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
</argLine>
<useSystemClassLoader>true</useSystemClassLoader> <!-- 使用系统类加载器 -->
<useManifestOnlyJar>false</useManifestOnlyJar> <!-- 禁用 ManifestOnlyJar -->
<systemProperties>
<property>
<!-- 配置 allure 结果存储路径 -->
<name>allure.results.directory</name>
<value>./allure-results</value>
</property>
</systemProperties>
</configuration>
<dependencies>
<!-- allure相关依赖 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
四、编写自动化脚本
对于代码的测试我们一般都是在test目录下创建,也可以在main方法中创建,但是一般规范都是让我们在test中创建,FirstTest用来编写我们的自动化脚本,run是执行我们的脚本
public void test(){
//自动下载与当前系统和浏览器版本匹配的驱动程序
WebDriverManager.chromedriver().setup();
//访问限制处理
ChromeOptions options=new ChromeOptions();
options.addArguments("--remote-allow-origins=*");
//生成一个浏览器对象
WebDriver driver=new ChromeDriver(options);
driver.get("https://www.baidu.com/");
driver.findElement(By.cssSelector("#kw")).sendKeys("鞠婧祎");
driver.findElement(By.cssSelector("#su")).click();
driver.quit();
}
当我们完成一次操作之后要关闭driver对象.[driver.quit();]

这样我们就完成了一次简单的简单的测试用例
五、元素的定位
一般定位一个元素我们一般使用cssSelector和Xpath.

获取web元素按照上述操作定位元素位置之后,右键可以复制 Selector和Xpath

5.1、通过id查找元素
// 通过id找到输入框
WebElement inputElement = driver.findElement(By.id("kw"));
5.2、通过class查找元素
WebElement inputElement = driver.findElement(By.className("s_ipt"));
5.3、通过name查找元素
WebElement inputElement = driver.findElement(By.name("wd"));
5.4、通过cssSelector来查找元素
//找到搜索框之后,输入搜索关键字鞠婧祎
driver.findElement(By.cssSelector("#kw")).sendKeys("鞠婧祎");
//点击按钮,也就是"百度一下".click(点击操作)
driver.findElement(By.cssSelector("#su")).click();
driver.quit();
5.5、通过XPATH来查找元素
XML路径语⾔,不仅可以在XML⽂件中查找信息,还可以在HTML中选取节点
xpath使⽤路径表达式来选择xml⽂档中的节点
xpath语法中:
获取HTML⻚⾯所有的节点
//*
获取HTML⻚⾯指定的节点
//[指定节点]
//ul :获取HTML⻚⾯所有的ul节点
//input:获取HTML⻚⾯所有的input节点
获取⼀个节点中的直接⼦节点
/
//span/input
获取⼀个节点的⽗节点
…
//input/… 获取input节点的⽗节点
实现节点属性的匹配
[@…]
//*[@id=‘kw’] 匹配HTML⻚⾯中id属性为kw的节点
使⽤指定索引的⽅式获取对应的节点内容
注意:xpath的索引是从1开始的。
百度⾸⻚通过://div/ul/li[3] 定位到第三个百度热搜标签
//使用Xpath定位
public void test02() {
createDriver();
driver.findElement(By.xpath("//*[@id="kw"]")).sendKeys("鞠婧祎");
driver.findElement(By.xpath("//*[@id="su"]")).click();
driver.quit();
}
六、常用测试方法
6.1 操作元素
// 输入文本
void sendKeys(CharSequence... keysToSend);
// 清空文本
void clear();
// 点击元素
void click();
// 提交表单
void submit();
// 模拟鼠标移动到元素并点击
Actions actions = new Actions(driver);
actions.moveToElement(element).click().perform();
// 执行JavaScript代码
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("window.scrollTo(0, document.body.scrollHeight)"); // 滚动到底部
6.2 获取内容
// 获取页面html
String getPageSource();
// 获取页面标题
String getTitle();
// 获取此元素(包括子元素)的可见(即未被CSS隐藏)文本
String getText();
// 获取此元素的标签名
String getTagName();
// 获取元素指定属性的值
String getAttribute(String name);
// 获取当前元素,基于样式的计算属性值
String getCssValue(String propertyName);
// 获取元素的尺寸及其在视口中的位置
Rectangle getRect();
publ
ic void test04() {
createDriver();
String text = driver.findElement(By.cssSelector("#hotsearch-content-wrapper > li:nth-child(1) > a")).getText();
System.out.println(text);
driver.quit();
}
6.3 页面请求
// 请求一个页面,不支持前进和后退切换
driver.get(url);
// 类似get,支持前进和后退切换
driver.navigate().to(url);
// 退到上一个页面,前提是必须前进了一个页面才能回退
driver.navigate().back();
// 指前进到下一个页面,前提是必须后退后才能前进
driver.navigate().forward();
// 刷新当前页面
driver.navigate().refresh();
6.4 窗口
句柄:每个浏览器窗口或标签页都有一个唯一的标识符(字符串形式),称为窗口句柄
// 切换到指定窗口
driver.switchTo().window(windowHandle);
// 切换到指定框架
driver.switchTo().frame(frameNameOrId);
// 切换到父框架
driver.switchTo().parentFrame();
// 切换到默认内容
driver.switchTo().defaultContent();
6.4.1 获取百度首页句柄以及新闻页面句柄
public void test06() {
createDriver();
//进入新闻页面
driver.findElement(By.cssSelector("#s-top-left > a:nth-child(1)")).click();
//获取百度首页句柄
String curHandle = driver.getWindowHandle();
System.out.println(curHandle);
System.out.println("========================");
//获取所有句柄
Set<String> windowHandles = driver.getWindowHandles();
for (String handle:windowHandles){
System.out.println(handle);
}
driver.quit();
}

6.4.2 切换句柄
当前driver对象指向的是百度首页的句柄,我们要使用新闻页的元素,就要切换窗口,让driver指向新闻页

6.4.3 设置窗口大小
//窗⼝最⼤化
driver.manage().window().maximize();
//窗⼝最⼩化
driver.manage().window().minimize();
//全屏窗⼝
driver.manage().window().fullscreen();
//⼿动设置窗⼝⼤⼩
driver.manage().window().setSize(new Dimension(1024, 768));
6.5 等待
6.5.1 强制等待
优点:代码简单
缺点:影响运行效率,浪费大量时间
Thread.sleep();
6.5.2 隐式等待
隐式等待是⼀种智能等待,他可以规定在查找元素时,在指定时间内不断查找元素。如果找到则代码继续执⾏,直到超时没找到元素才会报错。
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(3));
隐式等待作⽤域是整个脚本的所有元素。即只要driver对象没有被释放掉(driver.quit()),隐式等待就⼀直⽣效(全局生效).
但是隐式等待也有缺点,他只能查找元素是否存在,而不管元素对不对.而且只能查找元素
就像下方代码:
//等待机制的隐式等待
//隐式等待只是查找元素,并不关注元素结果对不对,只要是有结果,就继续执行
public void test13() throws InterruptedException {
createDriver();
driver.findElement(By.cssSelector("#kw")).sendKeys("邓紫棋");
driver.findElement(By.cssSelector("#su")).click();
Thread.sleep(3000);
driver.findElement(By.cssSelector("#\31 > div > div > div > div > div > div.header-wrapper_3m6nI > div.cos-row.row-text_1L24W.row_4WY55 > div > div > div.cos-flex.cos-items-center > div.title-wrapper_XLSiK > a > div > p > span > span"));
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(3));
//隐式等待,查找后发现有"#kw",所以不管.clear是否执行完成,就继续查找下一个元素是否存在
driver.findElement(By.cssSelector("#kw")).clear();
//隐式等待,查找后发现有"#kw",所以不管.sendKeys是否执行完成,就继续查找下一个元素是否存在
driver.findElement(By.cssSelector("#kw")).sendKeys("迪丽热巴");
//隐式等待,查找后发现有"#su",所以不管.click是否执行完成,就继续查找下一个元素是否存在
driver.findElement(By.cssSelector("#su")).click();
Thread.sleep(3000);
//如果我们不强制等待上述的三个指令执行完成的话,那么迪丽热巴这个词条可能还没完成输入(sendKeys("迪丽热巴");),点击查询按钮(.click();),隐式等待就已经查询完毕了
//此时迪丽热巴词条还没有进行搜索,就结束,所以还是会返回邓紫棋
//Thread.sleep(3000);就是为了等待 driver.findElement(By.cssSelector("#kw")).sendKeys("迪丽热巴");
// driver.findElement(By.cssSelector("#su")).click();执行完毕,更新#31 > div > div > div > div > div > div.header值为迪丽热巴
WebElement ele=driver.findElement(By.cssSelector("#\31 > div > div > div > div > div > div.header-wrapper_3m6nI > div.cos-row.row-text_1L24W.row_4WY55 > div > div > div.cos-flex.cos-items-center > div.title-wrapper_XLSiK > a > div > p > span > span"));
System.out.println(ele.getText());
driver.quit();
6.5.3 显式等待
显⽰等待也是⼀种智能等待,在指定超时时间范围内只要满⾜操作的条件就会继续执⾏后续代码
显式等待可以
elementToBeClickable:等待直到指定的元素在页面上可见并且可以被点击
WebDriverWait wait=new WebDriverWait(driver,Duration.ofSeconds(3));
wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("#id")));
等待某个元素的文本内容为 “预期文本”(就是看括号内文本在不在前端页面中)
wait.until(ExpectedConditions.textToBe());
presenceOfElementLocated(By locator) 是 ExpectedConditions 类中的一个方法,用于显式等待某个元素出现在页面的 DOM 中。这个方法并不保证元素是可见的或可交互的,只是确保元素已经存在于页面的 DOM 结构中
wait.until(ExpectedConditions.presenceOfElementLocated())
6.6 弹窗
弹窗不属于web页面元素,所以就没办法定位元素,这里就要使用Alert类
Alert alert = driver.switchTo.alert();
//确认
alert.accept()
//取消
alert.dismiss()
6.7 文件上传
点击⽂件上传的场景下会弹窗系统窗⼝,进⾏⽂件的选择。
selenium⽆法识别⾮web的控件,上传⽂件窗⼝为系统⾃带,⽆法识别窗⼝元素
但是可以使⽤sendkeys来上传指定路径的⽂件,达到的效果是⼀样的
WebElement ele = driver.findElement(By.cssSelector("body > div > div >
input[type=file]"));
//输入文件本地存储的路径即可
ele.sendKeys("D:\selenium2html\selenium2html\upload.html");
6.7.1文件操作工具类示例
package com.file;
import java.io.*;
public class ReadWriteFileUtils {
// 写入字节数组到文件
public static void writeByte(byte[] data, File file) {
try (FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos)) {
bos.write(data, 0, data.length);
} catch (IOException e) {
e.printStackTrace();
}
}
// 从文件读取字节数组
public static byte[] readByte(File file) {
byte[] data = null;
try (FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis)) {
data = new byte[(int) file.length()];
bis.read(data, 0, data.length);
} catch (IOException e) {
e.printStackTrace();
}
return data;
}
}
6.8 关闭和退出
//表示关闭当前标签页
driver.close();
//断开连接,关闭driver对象
driver.quit();
6.9 代理配置工具类示例
package com.proxy;
import org.openqa.selenium.Proxy;
import org.openqa.selenium.chrome.ChromeOptions;
public class ProxyUtils {
// 设置代理
public static void setProxy(ChromeOptions options, boolean enableProxy) {
if (enableProxy) {
String proxyAddress = "101.200.127.149:3129";
Proxy proxy = new Proxy();
proxy.setHttpProxy(proxyAddress);
options.setProxy(proxy);
}
}
}
6.10 随机用户代理工具类示例
package com.useragent;
import java.util.Random;
public class UserAgent {
public static String getUserAgentWindows() {
String[] userAgents = {
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0"
};
Random random = new Random();
return userAgents[random.nextInt(userAgents.length)];
}
}
6.11 截图并保存为文件
// 截图并保存为文件
File srcFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(srcFile, new File("/path/to/screenshot.png"));


