知识论坛
2024-10 ~ 2025-01
本项目是一个基于 SSM(Spring+SpringMVC+MyBatis)框架搭建的论坛系统。该系统为用户提供了一个开放、便捷的论坛交流平台。用户可以在论坛上发布主题帖、回复他人帖子,进行思想交流和问题讨论。系统具有完善的用户管理功能,包括注册、登录、个人资料设置等。通过 Spring 的依赖注入和面向切面编程,实现了代码的高内聚低耦合。MyBatis 方便地进行数据库操作,确保数据的高效存储和检索。SpringMVC 则负责处理用户请求和响应,提供流畅的用户体验。该论坛系统界面简洁美观,功能实用,能够满足不同用户的交流需求。
服务器:在线服务器
平台:Windows 10
浏览器:Chrome
自动化测试工具:Selenium
注入依赖
在maven-poom.xml文件中,我们引入了selenium自动测试化工具。并且引入了浏览器驱动(webdirvermanager)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>Blog</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>io.github.bonigarcia</groupId>
<artifactId>webdrivermanager</artifactId>
<version>5.8.0</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
但是在自动化测试流程中,驱动的使用非常频繁。频繁地创建和销毁驱动会带来较大的开销。为了优化这一过程,我们可以采用懒汉模式来加载驱动,确保在整个程序运行期间驱动只被创建一次(即实现单例模式),这样可以减少程序启动时的系统负担,因为驱动只有在被实际使用时才会被加载。当其他类需要利用这个驱动时,只需继承包含驱动加载逻辑的类即可。 此外,在测试用例出错时,为了查看当时的网页状况,我们需要进行屏幕截图以辅助问题排查。为此,我们可以在测试用例执行完毕后,使用 getScreenshotAs 方法来保存屏幕截图。为了方便管理这些截图,我们会在 Utils 类中添加一个保存截图的方法,并统一将截图保存到一个指定路径下,文件名以当前时间命名,以避免截图文件相互覆盖。这样,其他类可以方便地调用这个方法来实现屏幕截图的保存。
package common;
import io.github.bonigarcia.wdm.WebDriverManager;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.Duration;
public class Utils {
public static WebDriver driver;
//驱动
public static WebDriver createDriver(){
if (driver == null){
WebDriverManager.chromedriver().setup();
ChromeOptions options = new ChromeOptions();
//允许访问所有连接
options.addArguments("--remote-allow-origins=*");
driver = new ChromeDriver(options);
//隐式等待
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(2));
}
return driver;
}
public Utils(String url){
driver = createDriver();
driver.get(url);
}
//屏幕截图
public void getScreenShot(String str) throws IOException {
// ./src/test/image/
// /2024-07-17/
// /test01-17453010.png
// /test02-17452020.png
// /2024-07-18/
// /test01-174530.png
// /test02-174520.png
//屏幕截图
SimpleDateFormat sim1 = new SimpleDateFormat("yyyy-M-dd");
SimpleDateFormat sim2 = new SimpleDateFormat("HHmmssSS");
String dirTime = sim1.format(System.currentTimeMillis());
String fileTime = sim2.format(System.currentTimeMillis());
//./src/test/image/2024-07-17/test01(方法名str)-174530.png
String filename = "./src/test/image/"+dirTime+"/"+str + "-" + fileTime + ".png";
File srcFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
//scrFile放到指定位置
FileUtils.copyFile(srcFile,new File(filename));
}
}
当两次输入的密码不同时,注册失败
/当两次输入的密码不同,注册失败
public void enrollFal() throws IOException, InterruptedException {
// 通过见检查元素判断有没有打开注册页面
driver.findElement(By.cssSelector("#signUpForm > div > h2"));
// 输入用户名
driver.findElement(By.cssSelector("#username")).sendKeys("lihewu");
driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
// 输入昵称
driver.findElement(By.cssSelector("#nickname")).sendKeys("黎鹤舞");
driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
// 输入密码
driver.findElement(By.cssSelector("#password")).sendKeys("123456");
driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
// 确认密码
driver.findElement(By.cssSelector("#passwordRepeat")).sendKeys("111111");
driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
//点击复选框
driver.findElement(By.cssSelector("#policy")).click();
// 点击提交
driver.findElement(By.cssSelector("#submit")).click();
Thread.sleep(1000); // 显示等待
// 注册成功之后,判断是否会跳转回登录界面
driver.findElement(By.cssSelector("body > div > div > div > div:nth-child(1) > div > div.card.card-md > div > h2"));
}
当两次输入的密码相同时,注册成功,跳转到登录界面
public void enrollSuc() throws InterruptedException, IOException {
//通过是否查找到元素,判断是否成功跳转页面
driver.findElement(By.cssSelector("#signUpForm > div > div:nth-child(3) > label"));
driver.get(url);
// 通过见检查元素判断有没有打开注册页面
driver.findElement(By.cssSelector("#signUpForm > div > h2"));
// 输入用户名
driver.findElement(By.cssSelector("#username")).sendKeys("lihewu");
driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
// 输入昵称
driver.findElement(By.cssSelector("#nickname")).sendKeys("黎鹤舞");
driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
// 输入密码
driver.findElement(By.cssSelector("#password")).sendKeys("123456");
driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
// 确认密码
driver.findElement(By.cssSelector("#passwordRepeat")).sendKeys("123456");
driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
//点击复选框
driver.findElement(By.cssSelector("#policy")).click();
// 点击提交
Thread.sleep(2000);
driver.findElement(By.cssSelector("#submit")).click();
Thread.sleep(1000);
// 注册成功之后,判断是否会跳转回登录界面
driver.findElement(By.cssSelector("body > div > div > div > div:nth-child(1) > div > div.card.card-md > div > h2"));
// 进行截图,看当前是否跳转到了登录界面
driver.manage().timeouts().implicitlyWait(300, TimeUnit.MINUTES);
getScreenShot(getClass().getName());
System.out.println("注册成功");
}
测试用户名正确,密码错误,登录失败
public void loginFal(){
//刷新页面,保证输入框是空的
driver.navigate().refresh();
driver.findElement(By.cssSelector("#username")).sendKeys("zhouyi");
driver.findElement(By.cssSelector("#password")).sendKeys("");
driver.findElement(By.cssSelector("#submit")).click();
String res = driver.findElement(By.cssSelector("body > div.jq-toast-wrap.bottom-right > div > h2")).getText();
assert res.equals("警告");
}
登录成功后,跳转到论坛界面
public void LoginSuc() throws InterruptedException {
//刷新页面,保证输入框是空白
driver.navigate().refresh();
driver.findElement(By.cssSelector("#username")).sendKeys("zhouyi");
driver.findElement(By.cssSelector("#password")).sendKeys("123456");
driver.findElement(By.cssSelector("#submit")).click();
Thread.sleep(3000);
//用检查元素的方式检查结果是否成功
driver.findElement(By.cssSelector("#article_list_board_title"));
}
public class EditPageTest extends Utils {
public static String url="http://127.0.0.1:9580/index.html";
public EditPageTest() {
super(url);
}
public void EditSuc() throws InterruptedException {
driver.get(url);
driver.findElement(By.cssSelector("#bit-forum-content > div.page-header.d-print-none > div > div > div.col-auto.ms-a" +
"uto.d-print-none > div > a.btn.btn-primary.d-none.d-sm-inline-block.article_post")).click();
//输入标题
driver.findElement(By.cssSelector("#article_post_title")).sendKeys("测试");
//输入内容
WebElement ele =driver.findElement(By.cssSelector("#edit-article > div.CodeMirror.cm-s-default.CodeMirror-wrap.CodeMirror-empty > div.CodeMirror-scroll > div.CodeMirror-sizer > div > div > div > div.CodeMirror-code > div > pre"));
Actions action = new Actions(driver);
action.keyDown(Keys.ALT)
.sendKeys(ele,Keys.ARROW_RIGHT)
.keyUp(Keys.ALT)
.keyDown(Keys.SHIFT)
.sendKeys(Keys.ARROW_UP)
.keyUp(Keys.SHIFT)
.sendKeys(Keys.DELETE)
.perform();
action.sendKeys("这是通过selenium自动化输入的新的博客内容!!!").perform();
Thread.sleep(3000);
driver.findElement(By.cssSelector("#article_post_submit")).click();
}
}
public class UpdatePageTest extends Utils {
public static String url="http://127.0.0.1:9580/index.html";
public UpdatePageTest() {
super(url);
}
public void Update() throws InterruptedException {
//点击个人所在地
driver.findElement(By.cssSelector("#index_nav_avatar")).click();
//进入个人中心
driver.findElement(By.xpath("//*[@id=\"index_user_settings\"]")).click();
//是否有用户昵称
driver.findElement(By.cssSelector("#settings_nickname"));
//是否有“昵称”这两个字
driver.findElement(By.cssSelector(" #bit-forum-content > div.page-body > div > div > div > div.col.d-flex.flex-" +
"column > div > h3:nth-child(4)"));
//是否有“邮箱地址”这几个字
driver.findElement(By.cssSelector(" #bit-forum-content > div.page-body > div > div > div > div.col.d-flex.flex-" +
"column > div > h3:nth-child(7)"));
//是否有“电话号码”这几个字
driver.findElement(By.cssSelector(" #bit-forum-content > div.page-body > div > div > div > div.col.d-flex.flex-" +
"column > div > h3:nth-child(10)"));
//是否有“修改密码”这几个字
driver.findElement(By.cssSelector(" #bit-forum-content > div.page-body > div > div > div > div.col.d-flex.flex-" +
"column > div > h3:nth-child(13)"));
//是否有“提交修改”按钮
driver.findElement(By.cssSelector("#settings_submit_password"));
Thread.sleep(1000);
//3-修改昵称
//清除昵称的文本内容
driver.findElement(By.cssSelector("#setting_input_nickname")).clear();
//输入要修改的内容
driver.findElement(By.cssSelector("#setting_input_nickname")).sendKeys("lihewu02");
//点击修改按钮
driver.findElement(By.cssSelector("#setting_submit_nickname")).click();
//查看有没有修改成功
driver.findElement(By.cssSelector("body > div.jq-toast-wrap.bottom-right > div"));
Thread.sleep(3000);
System.out.println("昵称修改成功!");
}
}
public class BackPageTest extends Utils {
public static String url = "http://127.0.0.1:9580/index.html";
public BackPageTest() {
super(url);
}
public void Back() throws InterruptedException {
//2-点击我的帖子
driver.findElement(By.cssSelector("#index_nav_avatar")).click();
Thread.sleep(1000);
//点击退出按钮
driver.findElement(By.cssSelector("#index_user_logout")).click();
Thread.sleep(1000);
//获取当前的url地址
String expect = "http://101.200.198.144:58080/sign-in.html";
String actual = driver.getCurrentUrl();
//判断是否跳转到登录界面
driver.findElement(By.cssSelector("body > div > div > div > div:nth-child(1) > div > div.card.card-md > div > h2"));
}
}