一、项目背景
1.1 测试目标
验证论坛功能完整性,确保用户个人中心、发布/删除管理、模块分类控制、搜索功能等核心模块
符合需求。
1.2 项目技术栈
后端:Spring Boot/Spring MVC
数据库:MySQL
前端:原生 HTML/CSS/AJAX
二、测试分类
1、测试功能
测试用例:
1.1 登录模块
1.2 注册模块
1.3 论坛界面
1.4 帖子测试
1.5 个人中心测试
2、手动测试系统
1.1 注册页面
1.2 登录测试
登录失败
登录成功
1.3 模块分类
1.4 发布帖子
1.5 点赞帖子
1.6 回复帖子
1.7 删除帖子
1.8 搜索帖子
功能测试总结:
测试用例:60
功能覆盖率:97%
测试时间:2025-05-28 13.20 ~ 2025-05-28 13.40
测试方式:手动测试
通过率:100%,没有明显功能性错误
3、自动化测试
自动化测试覆盖模块:
注册页面,登陆页面,切换模块,发布帖子,点赞和回复,个人中心
自动化数据源码链接:
Forum · 小加油家/Java_house - 码云 - 开源中国
自动化代码展示:
工具类:
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 org.openqa.selenium.edge.EdgeDriver;
import org.openqa.selenium.edge.EdgeOptions;
import org.openqa.selenium.support.ui.WebDriverWait;import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.Duration;public class Utils {//创建一个公共的driverpublic static WebDriver driver;//判断driver是否为空public static WebDriver creat(){if(driver == null){//创建WebDriverManager.edgedriver().setup();EdgeOptions options = new EdgeOptions();//允许访问所有链接options.addArguments("--remote-allow-origins=*");driver = new EdgeDriver(options);}//添加隐式等待driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(2));return driver;}/*** 屏幕截图* 屏幕截图文件目录* ./src/test/java/images/* /2025-04-29/* /test01-20123010.png* /test02-20133510.png* /2025-04-30/* /test01-20123010.png* * /test02-20133510.png**str:方法名/类名*///截图public void getPicture(String str) throws IOException {//规定两个时间SimpleDateFormat sim1 = new SimpleDateFormat("yyyy-MM-dd");SimpleDateFormat sim2 = new SimpleDateFormat("HHmmssSS");//接收String dirTime = sim1.format(System.currentTimeMillis());String fileTime = sim2.format(System.currentTimeMillis());String name = "./src/test/image/" + dirTime + "/" + str + "-" + fileTime + ".png";File screenshotAs = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);FileUtils.copyFile(screenshotAs, new File(name));}//使用public Utils(String url){//得到driverdriver = creat();driver.get(url);}}
注册代码:
package tests;import common.Utils;
import org.openqa.selenium.By;import java.io.IOException;public class RegistrationPage extends Utils {//填写访问路径
// public static String url = "http://127.0.0.1:58080/sign-up.html"; //注册urlpublic static String url = "http://127.0.0.1:58080/sign-in.html"; //登录urlpublic RegistrationPage() {super(url);}//判断是否可以转页public void TurnPage() throws IOException, InterruptedException {driver.findElement(By.cssSelector("body > div > div > div > div:nth-child(1) > div > div.text-center.text-muted.mt-3 > a")).click();driver.findElement(By.cssSelector("#signUpForm > div > h2"));
// Register(); //调用方法查看是否可以连贯
// driver.quit();}//判断页面是否可以加载出来public void RegisterRight(){driver.findElement(By.cssSelector("#signUpForm > div > h2"));
// driver.quit();}//填写用户名,昵称,密码,认识密码,同意注册public void Register() throws IOException, InterruptedException {//写用户名driver.findElement(By.cssSelector("#username")).sendKeys("houqi");//写昵称driver.findElement(By.cssSelector("#nickname")).sendKeys("侯七");//写密码和确认密码driver.findElement(By.cssSelector("#password")).sendKeys("123456");driver.findElement(By.cssSelector("#passwordRepeat")).sendKeys("123456");//同意协议driver.findElement(By.cssSelector("#policy")).click();
// //等待2秒截图并截图
// Thread.sleep(2000);
// getPicture(RegistrationPage.class.getName());//点击注册driver.findElement(By.cssSelector("#submit")).click();driver.quit();}
}
登录代码:
package tests;import common.Utils;
import org.openqa.selenium.By;import java.io.IOException;public class LoginPage extends Utils {public static String url = "http://127.0.0.1:58080/sign-in.html"; //登录urlpublic LoginPage() {super(url);}//判断页面是否可以加载出来public void LoginRight(){driver.findElement(By.cssSelector("#submit"));driver.quit();}//登录测试public void Login() throws InterruptedException, IOException {driver.findElement(By.cssSelector("#username")).sendKeys("houqi");driver.findElement(By.cssSelector("#password")).sendKeys("123456");
// //等待2秒截图并截图
// Thread.sleep(2000);
// getPicture(LoginPage.class.getName());driver.findElement(By.cssSelector("#submit")).click();
// //等待2秒截图并截图
// Thread.sleep(2000);
// getPicture(LoginPage.class.getName());
// driver.quit();}
}
主界面代码:
package tests;import common.Utils;
import org.openqa.selenium.By;import java.io.IOException;public class ForumInfo extends Utils {public static String url = "http://127.0.0.1:58080/index.html"; //论坛页面urlpublic ForumInfo() {super(url);}//使用登录功能LoginPage loginPage = new LoginPage();//判断页面是否可以加载出来public void ForumRight() throws IOException, InterruptedException {loginPage.Login();driver.findElement(By.cssSelector("#article_list_board_title"));
// driver.quit(); //判断页面是否可以加载出来}//判断是否可以转模块public void Turn() throws IOException, InterruptedException {loginPage.Login();driver.findElement(By.cssSelector("#topBoardList > li:nth-child(2) > a > span.nav-link-title")).click();driver.findElement(By.cssSelector("#topBoardList > li:nth-child(3) > a")).click();driver.findElement(By.cssSelector("#topBoardList > li:nth-child(10) > a > span.nav-link-title")).click();
// //等待2秒截图并截图
// Thread.sleep(2000);
// getPicture(ForumInfo.class.getName());driver.quit();}//是否可以使用搜索public void Search() throws IOException, InterruptedException {loginPage.Login();driver.findElement(By.cssSelector("body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div.nav-item.d-none.d-md-flex.me-3 > div > form > div > input")).sendKeys("111");//等待2秒截图并截图Thread.sleep(2000);getPicture(ForumInfo.class.getName());driver.quit();}//是否可以点击发布帖子public void Publish() throws IOException, InterruptedException {loginPage.Login();driver.findElement(By.cssSelector("#bit-forum-content > div.page-header.d-print-none > div > div > div.col-auto.ms-auto.d-print-none > div > a.btn.btn-primary.d-none.d-sm-inline-block.article_post")).click();driver.findElement(By.cssSelector("#bit-forum-content > div.page-header.d-print-none > div > div > div > h2"));driver.quit();}//是否可以查看帖子public void Look() throws IOException, InterruptedException {loginPage.Login();driver.findElement(By.cssSelector("#artical-items-body > div > div > div.col > div.text-truncate > a > strong")).click();driver.findElement(By.cssSelector("#btn_details_send_message"));//等待2秒截图并截图Thread.sleep(2000);getPicture(ForumInfo.class.getName());driver.quit();}//是否可以查看个人中心public void Lookk() throws IOException, InterruptedException {loginPage.Login();driver.findElement(By.cssSelector("#index_nav_avatar")).click();driver.findElement(By.cssSelector("#index_user_settings")).click();driver.quit();}//是否可以切换黑夜模式public void Switch() throws IOException, InterruptedException {loginPage.Login();driver.findElement(By.cssSelector("body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > a.nav-link.px-0.hide-theme-dark > svg")).click();//等待2秒截图并截图Thread.sleep(2000);getPicture(ForumInfo.class.getName());driver.quit();}//是否可以查看信息public void Lookkk() throws IOException, InterruptedException {loginPage.Login();driver.findElement(By.cssSelector("body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > div > a > svg")).click();driver.findElement(By.cssSelector("#offcanvasEndLabel"));driver.quit();}
}
帖子发布代码:
package tests;import common.Utils;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;import java.io.IOException;public class Publish extends Utils {public static String url = "http://127.0.0.1:58080/index.html"; //论坛页面urlpublic Publish() {super(url);}//使用登录功能LoginPage loginPage = new LoginPage();//判断页面是否可以加载出来public void PublishRight() throws IOException, InterruptedException {loginPage.Login();driver.findElement(By.cssSelector("#article_list_board_title"));driver.quit();}//判断在主页面是否可以发帖子public void PublishContent() throws IOException, InterruptedException {Actions actions = new Actions(driver); //模拟键盘loginPage.Login();driver.findElement(By.cssSelector("#bit-forum-content > div.page-header.d-print-none > div > div > div.col-auto.ms-auto.d-print-none > div > a.btn.btn-primary.d-none.d-sm-inline-block.article_post")).click();driver.findElement(By.xpath("//*[@id=\"article_post_title\"]")).sendKeys("第一个自动化帖子");WebElement element = 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.doubleClick(element).perform();actions.moveToElement(element).sendKeys("这是一个自动化帖子").perform();WebElement element1 = driver.findElement(By.xpath("//*[@id=\"article_post_submit\"]"));Thread.sleep(2000);actions.click(element1).perform();
// //等待2秒截图并截图
// Thread.sleep(2000);
// getPicture(Publish.class.getName());driver.quit();}//判断切换模块是否可以发布帖子public void PublishContent2() throws IOException, InterruptedException {Actions actions = new Actions(driver); //模拟键盘loginPage.Login();driver.findElement(By.cssSelector("#topBoardList > li:nth-child(3) > a > span.nav-link-title")).click();driver.findElement(By.cssSelector("#bit-forum-content > div.page-header.d-print-none > div > div > div.col-auto.ms-auto.d-print-none > div > a.btn.btn-primary.d-none.d-sm-inline-block.article_post")).click();driver.findElement(By.cssSelector("#article_post_borad > option:nth-child(2)")).click();driver.findElement(By.xpath("//*[@id=\"article_post_title\"]")).sendKeys("第一个c++帖子");WebElement element = 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.doubleClick(element).perform();actions.moveToElement(element).sendKeys("这是一个c++自动化帖子").perform();WebElement element1 = driver.findElement(By.xpath("//*[@id=\"article_post_submit\"]"));Thread.sleep(2000);actions.click(element1).perform();//等待2秒截图并截图Thread.sleep(2000);getPicture(Publish.class.getName());driver.quit();}//判断帖子是否可以点赞public void Upvote() throws IOException, InterruptedException {loginPage.Login();driver.findElement(By.cssSelector("#artical-items-body > div:nth-child(1) > div > div.col > div.text-truncate > a > strong")).click();driver.findElement(By.cssSelector("#details_btn_like_count")).click();driver.quit();}//判断帖子发布是否可以重新编辑public void Redact() throws IOException, InterruptedException {loginPage.Login();driver.findElement(By.cssSelector("#artical-items-body > div:nth-child(1) > div > div.col > div.text-truncate > a > strong")).click();driver.findElement(By.cssSelector("#details_artile_edit > span")).click();driver.quit();}//判断帖子是否可以回复public void Reply() throws IOException, InterruptedException {Actions actions = new Actions(driver); //模拟键盘loginPage.Login();driver.findElement(By.cssSelector("#artical-items-body > div:nth-child(1) > div > div.col > div.text-truncate > a > strong")).click();WebElement element = driver.findElement(By.cssSelector("#article_details_reply > div.CodeMirror.cm-s-default.CodeMirror-wrap.CodeMirror-empty > div.CodeMirror-scroll > div.CodeMirror-sizer > div > div > div > div.CodeMirror-code > div > pre"));actions.doubleClick(element).perform();Thread.sleep(1000);actions.moveToElement(element).sendKeys("写的很好").perform();Thread.sleep(2000);WebElement element1 = driver.findElement(By.cssSelector("#details_btn_article_reply > span"));actions.click(element);driver.quit();}//判断帖子是否可以删除public void Delete() throws IOException, InterruptedException {loginPage.Login();//删之前截图//等待2秒截图并截图Thread.sleep(2000);getPicture(Publish.class.getName());driver.findElement(By.cssSelector("#artical-items-body > div:nth-child(1) > div > div.col > div.text-truncate > a > strong")).click();driver.findElement(By.cssSelector("#bit-forum-content > div.page-body > div > div > div:nth-child(1) > div.col-9.card.card-lg > div.card-footer.bg-transparent.mt-auto.justify-content-end > div > div:nth-child(3) > div > a > span")).click();driver.findElement(By.cssSelector("#details_artile_delete")).click();//删之后截图//等待2秒截图并截图Thread.sleep(2000);getPicture(Publish.class.getName());driver.quit();}
}
个人中心代码:
package tests;import common.Utils;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;import java.io.IOException;public class Centre extends Utils {public static String url = "http://127.0.0.1:58080/index.html"; //论坛页面urlpublic Centre() {super(url);}//使用登录功能LoginPage loginPage = new LoginPage();//判断页面是否可以加载出来public void CentreRight() throws IOException, InterruptedException {loginPage.Login();driver.findElement(By.cssSelector("#index_nav_avatar")).click();driver.findElement(By.cssSelector("#index_user_settings")).click();driver.findElement(By.cssSelector("#settings_avatar"));driver.quit();}//判断是否可以换头像public void Switch() throws IOException, InterruptedException {loginPage.Login();driver.findElement(By.cssSelector("#index_nav_avatar")).click();driver.findElement(By.cssSelector("#index_user_settings")).click();//进入页面driver.findElement(By.cssSelector("#bit-forum-content > div.page-body > div > div > div > div.col.d-flex.flex-column > div > div.row.align-items-center > div:nth-child(2) > a"));driver.quit();}//判断是否可以修改昵称public void SwitchName() throws IOException, InterruptedException {loginPage.Login();driver.findElement(By.cssSelector("#index_nav_avatar")).click();driver.findElement(By.cssSelector("#index_user_settings")).click();//进入页面driver.findElement(By.cssSelector("#setting_input_nickname")).click();driver.findElement(By.cssSelector("#setting_input_nickname")).clear();driver.findElement(By.cssSelector("#setting_input_nickname")).sendKeys("小侯七");driver.findElement(By.cssSelector("#setting_submit_nickname")).click();//等待2秒截图并截图Thread.sleep(2000);getPicture(Centre.class.getName());driver.quit();}//判断是否可以修改邮箱地址public void Email() throws IOException, InterruptedException {loginPage.Login();driver.findElement(By.cssSelector("#index_nav_avatar")).click();driver.findElement(By.cssSelector("#index_user_settings")).click();//进入页面driver.findElement(By.cssSelector("#setting_input_email")).click();driver.findElement(By.cssSelector("#setting_input_email")).clear();driver.findElement(By.cssSelector("#setting_input_email")).sendKeys("1234567@qq.com");driver.findElement(By.cssSelector("#setting_submit_email")).click();//等待2秒截图并截图Thread.sleep(2000);getPicture(Centre.class.getName());driver.quit();}//判断是否可以修改电话号码public void Phone() throws IOException, InterruptedException {loginPage.Login();driver.findElement(By.cssSelector("#index_nav_avatar")).click();driver.findElement(By.cssSelector("#index_user_settings")).click();//进入页面//下滑页面((JavascriptExecutor) driver).executeScript("window.scrollTo(0, 500)");driver.findElement(By.cssSelector("#setting_input_phoneNum")).sendKeys("123456789");driver.findElement(By.cssSelector("#setting_submit_phoneNum")).click();//等待2秒截图并截图Thread.sleep(2000);getPicture(Centre.class.getName());driver.quit();}//是否可以修改密码public void Code() throws IOException, InterruptedException {loginPage.Login();driver.findElement(By.cssSelector("#index_nav_avatar")).click();driver.findElement(By.cssSelector("#index_user_settings")).click();//进入页面//下滑页面((JavascriptExecutor) driver).executeScript("window.scrollTo(0, 1000)");Thread.sleep(1000);driver.findElement(By.cssSelector("#settings_input_oldPassword")).sendKeys("654321");driver.findElement(By.cssSelector("#settings_input_newPassword")).sendKeys("123456");driver.findElement(By.cssSelector("#settings_input_passwordRepeat")).sendKeys("123456");Thread.sleep(1000);driver.findElement(By.cssSelector("#settings_submit_password")).click();
// //等待2秒截图并截图
// Thread.sleep(2000);
// getPicture(Centre.class.getName());
// driver.quit();}//修改密码并且重新登录public void LoginAgain() throws IOException, InterruptedException {Code();driver.findElement(By.cssSelector("#username")).sendKeys("houqi");driver.findElement(By.cssSelector("#password")).sendKeys("123456");Thread.sleep(2000);driver.findElement(By.cssSelector("#submit")).click();//等待2秒截图并截图Thread.sleep(2000);getPicture(Centre.class.getName());driver.quit();}//修改个人简历public void Resume() throws IOException, InterruptedException {loginPage.Login();driver.findElement(By.cssSelector("#index_nav_avatar")).click();driver.findElement(By.cssSelector("#index_user_settings")).click();//进入页面//下滑页面((JavascriptExecutor) driver).executeScript("window.scrollTo(0, document.body.scrollHeight)");Thread.sleep(500);driver.findElement(By.cssSelector("#settings_textarea_remark")).sendKeys("我的简历修改");driver.findElement(By.cssSelector("#settings_submit_remark")).click();//等待2秒截图并截图Thread.sleep(2000);getPicture(Centre.class.getName());driver.quit();}
}
自动化测试总结:
测试用例:28
功能覆盖率:95%
框架:Selenium 4.0.0 + Maven
通过率:100%,没有发现功能性bug
测试时间:2025-05-28 14.00 ~ 2025-05-28 21.35
自动化屏幕关键截图:(通过截图和预期比较)完全一致
4、Jmeter梯度压力测试
线程组设计:
测试结果:
性能报告:
Jmeter性能压力测试报告总结:
测试用例:3
高频接口覆盖率:90%
软件:Apache Jmeter 5.5
通过率:76.97%
测试时间:2025-05-29 10.00 ~ 2025-05-29 12.58
结果分析:系统在测试过程中表现相对稳定,在高负载下,系统具有较好的并发处理能力
性能瓶颈:登录接口的响应时间在某些时刻显著增加,可能是性能瓶颈所在
三、测试结果评价
1、主功能测试通过,项目可以上线。
2、项目上线后高优观察线上数据,查看线上用户操作日志,及时跟进用户反馈。