前言
本篇使用Selenium3+Junit5对个人技术交流论坛进行简单的自动化测试,如有错误,请在评论区指正,让我们一起交流,共同进步!
文章目录
本文开始
1. 项目基础描述
项目介绍:
技术交流论坛基于 Spring Boot,MyBatis, MySQL等技术实现的一个前后端分离的一个项目;
主要功能页有:登录页、注册页、技术交流论坛列表展示页,帖子编辑发布和个人中心页。
测试主要页面:登录页面,注册页面,列表展示页面以及帖子编辑发布页,个人信息展示,退出操作功能。【都是基于常用的主要页面进行的】
2. 编写手工测试用例
3. 测试用例转自动化测试用例
3.1 前置准备操作
3.1.1 配置环境:
创建Maven项目,配置pom.xml文件
<dependencies>
<!--添加selenium依赖-->
<!-- 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>
<!--保存屏幕截图的包-->
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
<!--Junit5-->
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.9.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.junit.platform/junit-platform-suite -->
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-suite</artifactId>
<version>1.9.1</version>
</dependency>
</dependencies>
3.1.2 配置使用的公共类
原因:
1.每个测试用例都需要驱动,使用前置方法设置,后置方法释放驱动资源
2.配置一些公共方法,方便测试使用;如:截图方法,进入登录状态方法等
public class AutoTestUtils {
//每次测试都需要驱动,写一个公共类,实现代码复用
public static WebDriver webDriver;
@BeforeAll
public static void SetUp() {
if(webDriver == null) {
System.setProperty("webdriver.chrome.driver","C:\\Program Files\\Google\\Chrome\\Application\\chromedriver.exe");
webDriver = new ChromeDriver();
}
}
@AfterAll
static void TearDown() {
webDriver.quit();
}
/**
* 截图方法
*/
public static void saveScreenshot(WebDriver driver, String fileName) throws IOException {
File srcFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
// 确保截图目录存在
File screenshotDir = new File(SCREENSHOT_DIR);
if (!screenshotDir.exists()) {
screenshotDir.mkdirs();
}
// 拼接完整的文件路径
File destFile = new File(screenshotDir, fileName);
// 复制文件
FileUtils.copyFile(srcFile, destFile);
System.out.println("Screenshot saved as " + destFile.getAbsolutePath());
}
/**
* 获取当前截图时间-字符串
* @return
*/
public static String getCurrentShotTime() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd-HHmmss");
String timeName = sdf.format(System.currentTimeMillis());
return timeName;
}
/**
* 封装登录方法,方便以后调用;以后测试需要在登录状态下使用
*/
public static void login() throws InterruptedException {
//1.打开登录页面
webDriver.get("http://8.130.77.131:58080/sign-in.html");
//2.清楚之前的账号密码
webDriver.findElement(By.cssSelector("#username")).clear();
webDriver.findElement(By.cssSelector("#password")).clear();
//3.找到输入框,输入正确的账号和密码
webDriver.findElement(By.cssSelector("#username")).sendKeys("zhangsan");
webDriver.findElement(By.cssSelector("#password")).sendKeys("123");
//4.点击登录按钮
webDriver.findElement(By.cssSelector("#submit")).click();
sleep(3000);
}
}
3.1.3 项目目录 + 截图
3.2 编写自动化测试脚本
3.2.1 注册自动化测试
- 注册界面测试 - RegTest
1.获取驱动,打开注册界面
2.找到输入框,输入账号,昵称,密码,确认密码
3.点击确认协议
4.校验是否注册成功
5.注册失败,截图查看失败原因
成功注册
/**
* 成功注册的情况
*/
@Order(1)
@ParameterizedTest
@CsvSource(value = {"lisi,lisi,123,123"})
public void regSuccessTest(String username, String nickname,
String password, String passwordRepeat) throws InterruptedException {
//显示等待
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
//1.打开注册页面
webDriver.get("http://8.130.77.131:58080/sign-up.html");
//2.找到输入框,输入注册的账号和密码
webDriver.findElement(By.cssSelector("#username")).sendKeys(username);
webDriver.findElement(By.cssSelector("#nickname")).sendKeys(nickname);
webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
webDriver.findElement(By.cssSelector("#passwordRepeat")).sendKeys(passwordRepeat);
//4.点击同意协议
webDriver.findElement(By.cssSelector("#policy")).click();
//5.点击注册按钮
webDriver.findElement(By.cssSelector("#submit")).click();
//5.验证是否跳转到登录页
sleep(2000);
String currentUrl = webDriver.getCurrentUrl();
Assertions.assertTrue(currentUrl.contains("sign-in.html"));//查看是否包含关键词
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
}
注册失败情况
【注】编写的测试用例太多,取几个演示
@Order(2)
@ParameterizedTest
@CsvSource(value = {"wangwu,wangwu,123,1234"})
public void regFailTest(String username, String nickname,
String password, String passwordRepeat) throws InterruptedException, IOException {
//显示等待
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
//1.打开注册页面
webDriver.get("http://8.130.77.131:58080/sign-up.html");
//2.找到输入框,输入注册的账号和密码
webDriver.findElement(By.cssSelector("#username")).sendKeys(username);
webDriver.findElement(By.cssSelector("#nickname")).sendKeys(nickname);
webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
webDriver.findElement(By.cssSelector("#passwordRepeat")).sendKeys(passwordRepeat);
//3.错误截图,生成当前截图时间
String timeName = getCurrentShotTime();
String fileName = "regFail" + timeName + ".png";
sleep(2000);
saveScreenshot(webDriver,fileName);
//4.点击同意协议
webDriver.findElement(By.cssSelector("#policy")).click();
//5.点击注册按钮
webDriver.findElement(By.cssSelector("#submit")).click();
String timeName2 = getCurrentShotTime();
String fileName2 = "regClickFail" + timeName2 + ".png";
sleep(2000);
saveScreenshot(webDriver,fileName2);
}
/**
* 昵称为空 + 密码错误
*/
@Order(3)
@ParameterizedTest
@CsvSource(value = {"laoliu,laoliu,123,123"})
public void regNickNameNullTest(String username, String nickname,
String password, String passwordRepeat) throws InterruptedException, IOException {
//显示等待
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
//1.打开注册页面
webDriver.get("http://8.130.77.131:58080/sign-up.html");
//2.找到输入框,输入注册的账号和密码
webDriver.findElement(By.cssSelector("#username")).sendKeys(username);
webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
webDriver.findElement(By.cssSelector("#passwordRepeat")).sendKeys(passwordRepeat);
//3.点击同意协议
webDriver.findElement(By.cssSelector("#policy")).click();
//4.点击注册按钮
webDriver.findElement(By.cssSelector("#submit")).click();
//5.失败截图
String timeName = getCurrentShotTime();
String fileName = "regNickNameNull" + timeName + ".png";
sleep(2000);
saveScreenshot(webDriver,fileName);
}
测试结果:
失败截图查看原因
3.2.2 登录自动化测试
- 登录界面自动化测试 - LoginTest
1.获取驱动,打开登录界面
2.校验正常登录 - 多参数测试,多个测试用例
3.校验异常登录 - 错误的密码登录
4.对于多组测试,需要清空上次输入的内容
5.使用注解保证测试的顺序
成功登录情况
/**
* 正常登录情况
* 参数化登录:使用注解@CsvSource
*/
@Order(1)
@ParameterizedTest
@CsvSource({"zhangsan,123", "张三,123"})
public void logSuccessTest(String name, String password) throws InterruptedException {
//显示等待
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
//1.打开登录页面
webDriver.get("http://8.130.77.131:58080/sign-in.html");
//2.清楚之前的账号密码
webDriver.findElement(By.cssSelector("#username")).clear();
webDriver.findElement(By.cssSelector("#password")).clear();
//3.找到输入框,输入正确的账号和密码
webDriver.findElement(By.cssSelector("#username")).sendKeys(name);
webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
//4.点击登录按钮
webDriver.findElement(By.cssSelector("#submit")).click();
//5.验证是否跳转到列表页
// webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
sleep(2000);
String currentUrl = webDriver.getCurrentUrl();
Assertions.assertEquals("http://8.130.77.131:58080/index.html", currentUrl);
//6.多次登录,每次登录后退回登录页面
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
webDriver.navigate().back();
}
失败登录
/**
* 异常登录情况
* 输入错误的账号+密码
*/
@Disabled // 不运行注释
@Order(2)
@ParameterizedTest
@CsvSource(value = "zhangsan,1234")
public void failLogin(String name, String password) throws InterruptedException, IOException {
//1.打开登录页面
webDriver.get("http://8.130.77.131:58080/sign-in.html");
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
//2.输入账号:zhangsan,密码:1234
webDriver.findElement(By.cssSelector("#username")).sendKeys(name);
webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
Thread.sleep(2000);
//3.点击提交
webDriver.findElement(By.cssSelector("#submit")).click();
//4.获取提示信息文本:用户或密码错误
String text = webDriver.findElement(By.cssSelector("body > div.jq-toast-wrap.bottom-right > div")).getText();
System.out.println("提示信息:" + text);
//5.生成当前截图时间
String timeName = getCurrentShotTime();
String fileName = "loginFail" + timeName + ".png";
//6.调用截图方法
sleep(3000);
saveScreenshot(webDriver,fileName);
}
运行结果
错误情况截图
3.2.3 列表页自动化测试
- 遇到的bug:
- 操作:登录状态查看帖子列表
- 出现异常: no such element
- 原因:首页帖子页面还未渲染完毕,就捕获文本元素
- 解决:使用隐式等待
如:webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
登录状态下查看列表
/**
* 登录状态查看帖子列表
* 出现异常: no such element
* 原因:首页帖子页面还未渲染完毕,就捕获文本元素
* 解决:使用显示等待
*/
@Test
@Order(1)
public void showSuccess() throws InterruptedException {
//1.登录操作
login();
//2.显示首页帖子列表,查看第一天帖子信息
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
String actual_text = webDriver.findElement(By.cssSelector("#artical-items-body > div:nth-child(1) > div > div.col > div.text-truncate > a > strong")).getText();
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
//3.断言校验
Assertions.assertEquals("Java是如何练成的?", actual_text);
}
未登录状态下查看帖子页
/**
* 未登录页不能够查看帖子页
* 能够显示
*/
@Test
@Order(2)
public void showFail() throws InterruptedException, IOException {
//1.不进行登录,直接查看帖子页面
webDriver.get("http://8.130.77.131:58080/index.html");
//2.显示列表页,使用截图查看
String timeName = getCurrentShotTime();
String fileName = "showFail" + timeName + ".png";
//3.调用截图方法
sleep(3000);
saveScreenshot(webDriver,fileName);
}
运行结果
未登录错误情况截图
3.2.4 帖子编辑自动化测试
- 遇到bug:
- 操作:登录状态下进行帖子编辑
- 出现异常:ElementClickInterceptedException: element click intercepted: Element is not clickable at point (939, 1108)
- 原因:页面是异步加载,点击按钮未加载,就进行了的点击,导致元素点击中断,找不到点击位置
登录状态下进行帖子编辑
/**
* 登录状态下进行帖子编辑
* 出现异常:ElementClickInterceptedException: element click intercepted: Element is not clickable at point (939, 1108)
* 原因:页面是异步加载,点击按钮未加载,就进行了的点击,导致元素点击中断,找不到点击位置
*/
@Test
public void editSuccess() throws InterruptedException, IOException {
//1.进入登录状态
login();
//2.点击编辑帖子
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
webDriver.findElement(By.xpath("//*[@id=\"forum-content\"]/div[1]/div/div/div[2]/div/a[1]")).click();
//3.输入帖子标题
webDriver.findElement(By.xpath("//*[@id='article_post_title']")).sendKeys("EditTest");;
sleep(3000);
//4.查看发布帖子按钮
String text = webDriver.findElement(By.xpath("//*[@id='article_post_submit']")).getText();
Assertions.assertEquals("发 布", text);
sleep(3000);
webDriver.findElement(By.xpath("/html/body/div[1]/div/div[1]/div[2]/div/div/div[2]/div/a")).click();
String text1 = webDriver.findElement(By.cssSelector("body > div.jq-toast-wrap.bottom-right > div")).getText();
System.out.println("提示:" + text1);
//5.截图查看
String time = getCurrentShotTime();
String fileName = "editSuccess" + time + ".png";
sleep(2000);
saveScreenshot(webDriver, fileName);
}
未登录状态
/**
* 未登录状态,直接提示报错信息
*/
@Test
public void editFail() throws InterruptedException, IOException {
//1.直接进入编辑页面
webDriver.get("http://8.130.77.131:58080/index.html");
//2.截图获取信息
String time = getCurrentShotTime();
String fileName = "editFail" + time + ".png";
sleep(2000);
saveScreenshot(webDriver, fileName);
}
运行结果:
没有输入帖子内容,错误提示截图
3.2.5 个人中心自动化测试
登录状态下获取个人信息
/**
* 登录状态下,获取个人信息
*/
@Test
public void successShowPersonInfo() throws InterruptedException {
//1.进入登录状态
login();
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
//2.点击个人中心
webDriver.findElement(By.cssSelector("#index_nav_avatar")).click();//点击个人头像
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
webDriver.findElement(By.cssSelector("#index_user_settings")).click();//下拉列表中,点击个人中心
sleep(2000);
//3.获取用户昵称
String actual_text = webDriver.findElement(By.cssSelector("#setting_input_nickname")).getAttribute("value");
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
Assertions.assertEquals("zhangsan", actual_text);
}
未登录状态获取个人中心
@Test
public void failShowPersonInfo() throws InterruptedException, IOException {
//1.进入列表页
webDriver.get("http://8.130.77.131:58080/index.html");
//2.点击个人中心
webDriver.findElement(By.cssSelector("#index_nav_avatar")).click();//点击个人头像
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
webDriver.findElement(By.cssSelector("#index_user_settings")).click();//下拉列表中,点击个人中心
//3.截图查看提示
String timeName = getCurrentShotTime();
String fileName = "failShowPersonInfo" + timeName + ".png";
//3.调用截图方法
sleep(3000);
saveScreenshot(webDriver,fileName);
}
运行结果
未登录状态,错误提示截图
3.2.6 退出功能自动化测试
登录状态下退出
/**
* 登录状态点击退出
*/
@Test
public void backSucTest() throws InterruptedException {
//1.进入登录状态
login();
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
//2.点击个人中心
webDriver.findElement(By.cssSelector("#index_nav_avatar")).click();//点击个人头像
//3.点击退出
webDriver.findElement(By.xpath("//*[@id=\"index_user_logout\"]")).click();
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
//4.回到登录页面校验 “用户登录” 文本
String login_text = webDriver.findElement(By.cssSelector("body > div > div > div > div:nth-child(1) > div > div.card.card-md > div > h2")).getText();
Assertions.assertEquals("用户登录", login_text);
}
运行结果:
4.小结
考虑提升:
- 可以考虑使用PO模式,现在的代码将获取元素,操作元素,测试元素操作混在了一起,对于后期维护比较困难,使用PO模式改进,可以复用元素代码,让多个人写测试用例的耦合降低,也利用后期的维护工作;
后期注意
- 需要注意测试的执行顺序,不关注可能报错
- 对于多参数测试,需要清空上次输入数据,页面回退
- 测试用例并不是越多越好,覆盖较多功能较好
- 测试功能会有遗漏的情况,对于测试用例执行顺序会有错误情况
测试优势:
1.使用Junit5单元测试框架中的注释:提高测试的稳定性,提高自动化执行效率;(指定执行测试顺序,指定参数)
2.根据技术交流论坛设计的手工测试用例,对每个测试用例的常用功能实现自动化测试
3.使用工具类每次测试都需要驱动,写一个公共类,实现代码复用
4.使用等待:提高自动化运行效率,提高自动化的稳定性,减小误报的可能性
总结
✨✨✨各位读友,本篇分享到内容如果对你有帮助给个👍赞鼓励一下吧!!
感谢每一位一起走到这的伙伴,我们可以一起交流进步!!!一起加油吧!!!