Java+testNG+Selenium

Selenium导入相关的依赖包到pom.xml演示:
在pom.xml里导入下面的依赖包:

<!--selenium start -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.10.0</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.0.1-jre</version>
</dependency>
<!--selenium end -->

Maven-->clean、install(Run Maven Build),构建成功后,刷新一下项目就看到了
webdriver浏览器驱动包配置以及注意事项和常用问题处理:
在https://googlechromelabs.github.io/chrome-for-testing/地址下找到匹配浏览器版本的驱动,下载完成后解压,复制一下,找到Google浏览器,右键属性,点击打开文件所在位置,如下图:

image

粘贴驱动到浏览器安装路径,如下图:

image

放到这里就好了,然后要复制这个路径(C:\Program Files\Google\Chrome\Application),以后会用到

Selenium元素定位案例实战:
在baidu下新增一个包,
selenium.test,在该包下新增一个类,OpenBaiduTest.java,新增代码如下:

package com.baidu.selenium.test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver; // 手动导入
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.Test;

/*
* 1、设置浏览器驱动路径C:\Program Files\Google\Chrome\Application
* 2、实例化webDriver
* 3、打开网页地址
* 4、定位元素
* 5、搜索
* 6、停留多少秒
* 7、退出浏览器
* */
public class OpenBaiduTest {
public WebDriver driver;
@Test
public void openBaidu() throws InterruptedException{
// 第一步、设置浏览器驱动路径,驱动和浏览器的版本号前三位必须一致
System.setProperty("webdriver.chrome.driver", "C:\\Program Files\\Google\\Chrome\\Application\\chromedriver.exe");
// 第二步、new浏览器驱动对象
driver = new ChromeDriver();
// 第三步、打开网页
driver.get("https://www.baidu.com");
// 第四步、搜索java
driver.findElement(By.id("chat-textarea")).sendKeys("java");
// 第五步、停留3s
Thread.sleep(3000);
// 第六步、关闭浏览器
driver.quit();
}
}

Selenium代码模块化封装案例实战:
所有的操作都是写在同一个方法,浏览器的驱动位置设置,打开浏览器,关闭浏览器都是在同一个方法里面,需要不同操作的代码进行模块化,需要定义三个方法:
1、把浏览器测试准备工作定义一个方法
2、业务逻辑处理定义一个方法
3、测试完成之后工作定义一个方法
新建一个类,
TestCaseOpenBaidu.java,新增代码如下:

package com.baidu.selenium.test;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

public class TestCaseOpenBaidu {
private WebDriver driver;
public String url="https://www.baidu.com";
@BeforeClass
public void setUpEnv(){
System.setProperty("webdriver.chrome.driver", "C:\\Program Files\\Google\\Chrome\\Application\\chromedriver.exe");
driver = new ChromeDriver();
}
@Test
public void openBaidu(){
// 设置浏览器窗口大小,设置为最大窗口
driver.manage().window().maximize();
// 打开浏览器访问地址
driver.get(url);
// 输入框中间输入C++
driver.findElement(By.id("chat-textarea")).sendKeys("C++");
// 输入之后,点击搜索
driver.findElement(By.id("chat-submit-button")).click();
}
// 浏览器测试后的工作
@AfterClass
public void tearDown() throws InterruptedException{
Thread.sleep(3000);
driver.quit();
}

}

selenium+testng自动化测试框架设计案例实战之DataProvider:
测试场景:
测试多个用户的账户登录,假如有50个用户,需要测试登录,你会怎么测试呢?
1、写50个测试脚本去验证登录(不可取,如果有1000、10000个,那不得累死,费力不讨好)
2、采用DDT,把用户名和密码写到一个表格里,然后依次从表格读取去运行这个登录用例,定义一个二维数组,进行参数化
如果只有一个或者两个用户,这两种方法基本上没有什么区别,有时候第一个比第二个还简单,这就得灵活判断了,也就是所说的经验

DataProvider数据驱动参数化用户数据案例实战:
新建一个类,
TestDDT.java,先创建一个二维数组的方法,在写业务代码,新增代码如下:

package com.baidu.selenium.test;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

/*
* dataprovider进行参数化
* 写一个登录百度的方法,输入用户名和密码
* 1、设置浏览器驱动包的位置
* 2、new webDriver
* 3、元素定位,定位登录用户名和密码,先清空输入框中间内容,然后输入参数化的值
* 4、关闭浏览器,quit()
* */
public class TestDDT {
@Test(dataProvider = "testdata")
// 编写业务代码
public void testLogin(String username, String password) throws InterruptedException{
// 设置浏览器驱动包的位置
System.setProperty("webdriver.chrome.driver", "C:\\Program Files\\Google\\Chrome\\Application\\chromedriver.exe");
WebDriver driver = new ChromeDriver();
// 设置浏览器大小,全屏显示浏览器,设置最大
driver.manage().window().maximize();
driver.get("https://www.baidu.com");
// 打开浏览器,停留3000ms
Thread.sleep(3000);
// 点击登录按钮
driver.findElement(By.xpath("//*[@id=\"s-top-loginbtn\"]")).click();
Thread.sleep(2000);
// 定位用户名输入框元素,先清空输入框中间内容,然后在输入值,用户名
driver.findElement(By.xpath("//*[@id=\"TANGRAM__PSP_11__userName\"]")).clear();
driver.findElement(By.xpath("//*[@id=\"TANGRAM__PSP_11__userName\"]")).sendKeys(username);
// 定位密码输入框元素,先清空输入框中间内容,然后在输入值,密码
Thread.sleep(2000);
driver.findElement(By.xpath("//*[@id=\"TANGRAM__PSP_11__password\"]")).clear();
driver.findElement(By.xpath("//*[@id=\"TANGRAM__PSP_11__password\"]")).sendKeys(password);
Thread.sleep(5000);
System.out.println("browser will be close"); // 每运行一次,打印一行
// 关闭浏览器并退出
driver.quit();
}
@DataProvider(name = "testdata")
public Object[][] TestDataFeed(){
// 创建一个二维数组
Object[][] baidudata = new Object[3][2];
baidudata = new Object[][]{
{"test@gmail.com", "test@gmail.com"},
{"test@yahoo.com", "test@yahoo.com"},
{"489523309@qq.com", "489523309@qq.com"}
};
System.out.println(baidudata);
return baidudata;
}
}

运行成功,每次打印出browser will be close并关闭浏览器

数据驱动测试DDT利用POI读取excel文件内容项目实战:
上面的方法不是很灵活,要是数据变化了还要修改代码,数据驱动测试把需要的数据通过excel表格进行管理,POI去读取表格的数据进行参数化,数据和业务代码进行分离,新增一个类,
TestNGDDTPoiTest.java,新增代码如下:

package com.baidu.selenium.test;

import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import java.io.File;
import java.io.FileInputStream;

public class TestNGDDTPoiTest {
@Test(dataProvider = "testdata")
// 编写业务代码
public void testLogin(String username, String password) throws InterruptedException{
// 设置浏览器驱动包的位置
System.setProperty("webdriver.chrome.driver", "C:\\Program Files\\Google\\Chrome\\Application\\chromedriver.exe");
WebDriver driver = new ChromeDriver();
// 设置浏览器大小,全屏显示浏览器,设置最大
driver.manage().window().maximize();
driver.get("https://www.baidu.com");
// 打开浏览器,停留3000ms
Thread.sleep(3000);
// 点击登录按钮
driver.findElement(By.xpath("//*[@id=\"s-top-loginbtn\"]")).click();
Thread.sleep(2000);
// 定位用户名输入框元素,先清空输入框中间内容,然后在输入值,用户名
driver.findElement(By.xpath("//*[@id=\"TANGRAM__PSP_11__userName\"]")).clear();
driver.findElement(By.xpath("//*[@id=\"TANGRAM__PSP_11__userName\"]")).sendKeys(username);
// 定位密码输入框元素,先清空输入框中间内容,然后在输入值,密码
Thread.sleep(2000);
driver.findElement(By.xpath("//*[@id=\"TANGRAM__PSP_11__password\"]")).clear();
driver.findElement(By.xpath("//*[@id=\"TANGRAM__PSP_11__password\"]")).sendKeys(password);
Thread.sleep(5000);
System.out.println("browser will be close");
// 关闭浏览器并退出
driver.quit();
}

@DataProvider(name = "testdata")
public Object [][] TestDataFeed() throws Exception{
// 通过数据流的方式读取excel
File src = new File("D:\\testdata.xlsx"); // excel里有5条数据
FileInputStream fis = new FileInputStream(src);

@SuppressWarnings("resource")
XSSFWorkbook wb = new XSSFWorkbook(fis);
XSSFSheet sh1 = wb.getSheetAt(0);
int numberrow = sh1.getPhysicalNumberOfRows();
Object [][] baidudata = new Object[numberrow][2];
for(int i=0; i < numberrow; i++){
baidudata[i][0] = sh1.getRow(i).getCell(0).getStringCellValue();
baidudata[i][1] = sh1.getRow(i).getCell(1).getStringCellValue();
}
return baidudata; // 返回一个二维数组
}
}

excel里输入截图如下:

image

运行成功,打印5个browser will be close,如下图:

image

selenium+testng自动化测试框架项目实战项目业务介绍:
项目业务背景介绍,通过自动化测试脚本验证各模块功能是否正常
自动化测试框架搭建的准备工作:
1、需要通过pom.xml导入相关的依赖包
2、DDT进行数据的参数化,DDT驱动POI依赖包,读取excel表格中间的数据进行参数化
3、浏览器相关驱动的准备工作
4、编写自动化测试业务代码
5、需要编写自动化测试报告
6、testng.xml文件对相关的测试集进行管理

数据驱动测试DDT利用POI读取excel文件代码实现:
编写业务代码之前先需要对数据进行参数化,方便后续调用这一块的数据,测试数据通过excel进行维护,业务代码通过代码模块进行维护和管理,数据和业务代码完全分离,新建一个包,
com.selenium.testerhome.business,包下新建一个类,BasicBusiness.java,新增代码如下:

package com.selenium.testerhome.business;

import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.testng.annotations.DataProvider;

import java.io.File;
import java.io.FileInputStream;

public class BasicBusiness {
// 数据驱动测试DDT,利用POI去读excel表格中间文件
@DataProvider(name = "userdata")
public Object[][] signData() throws Exception{
// 通过数据流的方式读取excel
File src = new File("D:\\testerhomeuser.xlsx");
FileInputStream fis = new FileInputStream(src);

@SuppressWarnings("resource")
XSSFWorkbook wb = new XSSFWorkbook(fis);
XSSFSheet sh1 = wb.getSheetAt(0);
int numberrow = sh1.getPhysicalNumberOfRows();
Object [][] userdata = new Object[numberrow][2];
for(int i=0; i < numberrow; i++){
userdata[i][0] = sh1.getRow(i).getCell(0).getStringCellValue();
userdata[i][1] = sh1.getRow(i).getCell(1).getStringCellValue();
}
return userdata; // 返回一个二维数组
}
}

selenium浏览器驱动设置模块化代码实现:
浏览器测试准备工作,加载驱动,设置浏览器驱动包路径,根据上面的代码继续编写代码,新增代码如下:

// 浏览器准备工作,加载浏览器驱动
private WebDriver driver;
// 浏览器的准备工作在整个类中间都需要做beforeclass
@BeforeClass
public void setUpEnv(){
// 设置浏览器驱动包位置
System.setProperty("webdriver.chrome.driver", "C:\\Program Files\\Google\\Chrome\\Application\\chromedriver.exe");
// new google浏览器驱动对象
driver = new ChromeDriver();
Reporter.log("浏览器测试准备工作,加载浏览器驱动");
}

项目实战浏览器初始设置以及项目首页模块自动化测试代码实现:
接下来访问项目首页,新增代码如下:

@Test
// 设置浏览器大小,以及访问的项目的首页
public void openTesterHome(){
// 设置浏览器窗口大小,设置为最大窗口
driver.manage().window().maximize();
// 打开浏览器,访问https://testerhome.com/
driver.get("https://testerhome.com/");
// 访问成功,输入日志
Reporter.log("访问项目工程地址是否正常");

项目实战自动化测试业务逻辑代码实现以及priority实现:
接下来访问项目首页,新增代码如下:

// 需要校验访问首页是否是成功的,需要获取文本信息进行匹配,如果正确代表成功
// contains(text())
@Test(priority = 1)
// 访问首页是否成功,访问到首页,包含登录的文本字眼,代表成功
public void openTesterHomeSuccess(){
// link_text,通过超链接完整文本定位,并获取文本信息,如果匹配代表访问链接地址正确
String logintext = driver.findElement(By.linkText("登录")).getText();
System.out.println(logintext);
// 定位包含文本"测试之家"contains(text())
String hometext = driver.findElement(By.xpath("//*[contains(text(),'测试之家')]")).getText();
System.out.println(hometext);
Reporter.log("验证项目地址内容是否正常,界面内容包含指定内容代表成功");
}

运行成功,打印登录和测试之家

用户注册模块自动化测试代码编写:
还是在
BasicBusiness.java里,新增注册的代码,如下:

// 用户注册模块自动化测试代码编写
@Test(priority = 2)
public void signUp(){
// 需要停留1000ms
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 通过linkText元素定位,进行点击
driver.findElement(By.linkText("注册")).click();
Reporter.log("用户注册");
}

把光标放到sleep(标红)上面, 按住Alt+Enter,弹出提示框,点击Surround with try/catch,sleep就不标红了,运行,点击注册,打开注册页面

用户登录模块自动化测试代码实现:
登录模块自动化测试脚本实现:
1、需要跳转到登录页面
2、需要读取DDT测试数据驱动读取表格中间参数化数据
3、用户名和密码输入框内容清空,然后输入用户名和密码的内容,内容来源于参数化的数据
4、通过元素定位点击登录按钮

BasicBusiness.java里,新增代码如下:

@Test(priority = 3)
public void signIn() throws InterruptedException{
Thread.sleep(2000);
// link_text:通过超链接的完整文本定位,并点击该超链接
driver.findElement(By.linkText("登录")).click();
Reporter.log("用户登录跳转到登录页面");
// System.out.println("是否执行到这一步");
// 定位包含文本"测试之家"的元素 contains(text(), '测试之家')
// String hometext = driver.findElement(By.xpath("//*[contains(text(),'测试之家')]")).getText();
// System.out.println(hometext);
// Reporter.log("验证https://www.testerhome.com/地址内容是否正确");
}
// 这个方法对登录做对应的操作
@Test(dataProvider = "userdata", priority = 4)
public void signInBusiness(String username, String password) throws InterruptedException{
// 等待3秒
Thread.sleep(3000);
// 通过ID定位元素,先对用户名输入框进行清空,以免输入框中间有值
driver.findElement(By.id("user_login")).clear();
driver.findElement(By.id("user_login")).sendKeys(username);
// 通过ID定位元素,先对密码输入框进行清空,以免输入框中间有值
driver.findElement(By.id("user_password")).clear();
driver.findElement(By.id("user_password")).sendKeys(password);
// 点击登录按钮
driver.findElement(By.name("commit")).click();
Reporter.log("输入用户名和密码,用户登录成功,用户名:"+username+"用户密码信息:"+password);
}

运行成功,所有方法都实现了,如下图所示:

image

个人中心模块自动化测试代码实现:
验证登录是否成功,登录成功的页面能看到jack_testerhome,新增代码如下:

@Test(priority = 5)
// 校验个人中心登录是否成功,匹配到内容代表个人中心登录成功
public void signInSuccess(){
// link_text:通过超链接的完整文本定位,并获取文本信息,如果匹配代表访问成功
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String logintext = driver.findElement(By.linkText("jack_testerhome")).getText();
System.out.println(logintext);
Reporter.log("登录成功跳转到个人中心界面是否正常");
}

运行成功,打印出jack_testerhome

社区模块和招聘模块自动化测试用例代码实现:
登录成功后可以看到社区和招聘超链接,点击超链接看功能是否正常,新增代码如下:

@Test(priority = 6)
public void getCommunity(){
// link_text:通过超链接的完整文本定位,并获取文本信息,如果匹配代表访问链接地址正确
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 通过元素定位linkText,进行点击click()
driver.findElement(By.linkText("社区")).click();
Reporter.log("社区模块功能是否正常");
}

@Test(priority = 8)
public void getRecruit(){
// link_text:通过超链接的完整文本定位,并获取文本信息,如果匹配代表访问链接地址正确
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 通过元素定位linkText,进行点击click()
driver.findElement(By.linkText("招聘")).click();
Reporter.log("招聘模块功能是否正常");
}

开源项目和活动模块自动化测试脚本代码实现:
登录成功后可以看到开源项目和活动超链接,点击超链接看功能是否正常,新增代码如下:

@Test(priority = 8)
// 开源项目自动化测试脚本编写
public void getOpenSourceProjects(){
// link_text:通过超链接的完整文本定位,并获取文本信息,如果匹配代表访问链接地址正确
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 通过元素定位linkText,进行点击click()
driver.findElement(By.linkText("开源项目")).click();
Reporter.log("开源项目模块功能是否正常");
}

@Test(priority = 9)
// 活动自动化测试脚本编写
public void getActivity(){
// link_text:通过超链接的完整文本定位,并获取文本信息,如果匹配代表访问链接地址正确
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 通过元素定位linkText,进行点击click()
driver.findElement(By.linkText("活动")).click();
Reporter.log("活动模块功能是否正常");
}

@Test(priority = 10)
// Wiki自动化测试脚本编写
public void getWiKi(){
// link_text:通过超链接的完整文本定位,并获取文本信息,如果匹配代表访问链接地址正确
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 通过元素定位linkText,进行点击click()
driver.findElement(By.linkText("Wiki")).click();
Reporter.log("Wiki模块功能是否正常");
}

项目实战执行完成所有测试用例退出系统资源释放代码实现:
所用用例执行完成后点需要退出系统,关闭浏览器,新增代码如下:

@Test(priority = 11)
// priority = 11,最后去执行,整个用例执行完成,推出系统,资源进行回收,所有测试用例执行完成之后需要推出系统,driver.quit()
public void quitTesterHome(){
// link_text:通过超链接的完整文本定位,并获取文本信息,如果匹配代表访问链接地址正确
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
driver.quit();
Reporter.log("系统运行正常,关闭浏览器退出系统");
}

ReporterListener美化测试报告代码实现:

package com.selenium.testerhome.listener; // 放到哪个路径下就把包名改一下

import com.aventstack.extentreports.ExtentReports;
import com.aventstack.extentreports.ExtentTest;
import com.aventstack.extentreports.Status;
import com.aventstack.extentreports.reporter.ExtentSparkReporter;
import com.aventstack.extentreports.reporter.configuration.Theme;
import org.testng.*;
import org.testng.xml.XmlSuite;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
* ExtentReport 美化版 TestNG 监听器
*/
public class ExtentTestNGIReporterListener implements IReporter {

private ExtentReports extent;

@Override
public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory) {
// 时间戳,防止覆盖报告
String time = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss").format(new Date());
String reportPath = System.getProperty("user.dir")
+ File.separator + "test-output"
+ File.separator + "TestReport_" + time + ".html";

// 初始化报告
ExtentSparkReporter reporter = new ExtentSparkReporter(reportPath);
extent = new ExtentReports();
extent.attachReporter(reporter);

// ===================== 美化配置 =====================
reporter.config().setTheme(Theme.DARK); // 深色主题
reporter.config().setDocumentTitle("自动化测试报告");
reporter.config().setReportName("接口自动化测试");
reporter.config().setEncoding("UTF-8");
reporter.config().setTimeStampFormat("yyyy-MM-dd HH:mm:ss");

// 系统信息
extent.setSystemInfo("测试人员", "测试开发");
extent.setSystemInfo("环境", "测试环境");
extent.setSystemInfo("操作系统", System.getProperty("os.name"));
extent.setSystemInfo("JDK版本", System.getProperty("java.version"));

// ===================== 构建报告内容 =====================
for (ISuite suite : suites) {
Map<String, ISuiteResult> results = suite.getResults();
for (ISuiteResult result : results.values()) {
ITestContext context = result.getTestContext();

buildTest(context.getPassedTests(), Status.PASS);
buildTest(context.getFailedTests(), Status.FAIL);
buildTest(context.getSkippedTests(), Status.SKIP);
}
}

extent.flush();
System.out.println("======================================");
System.out.println("✅ 美化报告已生成:");
System.out.println(reportPath);
System.out.println("======================================");
}

private void buildTest(IResultMap resultMap, Status status) {
if (resultMap.size() > 0) {
for (ITestResult result : resultMap.getAllResults()) {
String testName = result.getMethod().getMethodName();
ExtentTest test = extent.createTest(testName);

// 执行时间
test.getModel().setStartTime(new Date(result.getStartMillis()));
test.getModel().setEndTime(new Date(result.getEndMillis()));

// 状态
test.log(status, "用例执行结果:" + status);

// 失败显示异常
if (result.getThrowable() != null) {
test.fail(result.getThrowable());
}
}
}
}
}

testng.xml统一管理所有测试用例并执行:
通过xml文件管理对应的测试用例,pom.xml可以对所有的testng.xml文件进行统一管理,只需要运行pom.xml就可以

image

项目实战输出自动化测试报告测试结果进行分析:

image

 

 

posted @ 2026-03-09 11:33  laosun0204  阅读(23)  评论(0)    收藏  举报