目录
一、项目的介绍
二、项目功能
三、测试项目
1.编写测试用例编辑
2.执行部分测试用例
3.自动化测试
1)添加相关Maven依赖(pom.xml)
2)编写论坛系统的界面测试用例
3)编写自动化代码测试部分测试用例
4.性能测试
一、项目的介绍
本项目是基于 Spring 开发的前后端分离的论坛系统。
在该项目的开发中使用到 SpringBoot 构建项目基础框架 、SpringMVC 开发 Web 应用程序 及 mybatis-plus 来操作数据库等。
二、项目功能
本项目实现了登录,注册,展示用户信息,修改用户信息,发布帖子,查看帖子,点赞帖子,回复帖子,用户间私聊等功能。
登录界面:
注册界面:
论坛页面展示:
帖子内容与帖子回复:
用户信息展示:
收到的私信:
三、测试项目
1.编写测试用例

2.执行部分测试用例
登录界面测试:
1)输入正确的用户名与密码 -- 登录成功进入首页
2)输入错误的用户名 -- 提示用户名错误
3)输入错误的密码 -- 提示密码错误
注册界面测试:
1)输入基本的注册信息 -- 成功注册并跳转登录界面
2)输入存在的用户名 -- 提示用户名已存在
3)密码与确认密码不一致 -- 提示检查确认密码
个人中心测试:
修改个人信息 -- 提示修改成功并更换页面信息:
修改前:
修改后:
发帖测试:
发送帖子 -- 提示发送成功并在首页显示帖子 :
发送私信测试
给用户发送私信 -- 提示发送成功,接受者收到私信
3.自动化测试
1)添加相关Maven依赖(pom.xml)
<dependencies><!-- 用来自动下载浏览器驱动 --><dependency><groupId>io.github.bonigarcia</groupId><artifactId>webdrivermanager</artifactId><version>5.8.0</version><scope>test</scope></dependency><!-- 用来自动化Web浏览器操作 --><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>
2)编写论坛系统的界面测试用例
3)编写自动化代码测试部分测试用例
Utils类:
用来定义不同页面测试所用到的公共属性(例如:浏览器驱动),定义一些公共方法,(例如:屏幕截图,创建浏览器驱动package common; import io.github.bonigarcia.wdm.WebDriverManager; import org.apache.commons.io.FileUtils; import org.openqa.selenium.By; 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.support.ui.WebDriverWait; import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.time.Duration;public class Utils {// 定义浏览器驱动public static WebDriver driver = null;public WebDriverWait wait = null;public Utils(String url) {//调用driver对象driver = createDriver();// 显示等待wait = new WebDriverWait(driver, Duration.ofSeconds(2));// 浏览器跳转到 URL 界面driver.get(url);}// 创建浏览器驱动private 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(3));}return driver;}// 屏幕截图public void screenshot(String str,String describe) 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());// ./src/test/java/images/2025-04-14/test01/描述13972011.pngString filename = "./src/test/java/images/"+ dirTime + "/" + str + "/" + describe +fileTime + ".png";File image = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);FileUtils.copyFile(image,new File(filename));}// 从提示弹窗中获取文本public String getTestFromAler(String path) {String text = driver.findElement(By.xpath(path)).getText();text = text.replace("\n","").substring(3);return text;} }
LoginTest类:
用来自动化测试登录界面package tests; import common.Utils; import org.openqa.selenium.By; import java.io.IOException;// 自动化测试登录界面 继承 Utils 类就能使用 Utils 创建好的浏览器驱动和一些公共方法 public class LoginTest extends Utils {// 登录界面的URLprivate static String url = "http://127.0.0.1:58080/sign-in.html";public LoginTest() {super(url);}// 检查元素是否存在 -- 不存在就报错public void checkEleExist() {// 检查用户名输入框是否存在driver.findElement(By.cssSelector("#username"));// 检查密码输入框是否存在driver.findElement(By.cssSelector("#password"));// 检查登录按钮是否存在driver.findElement(By.cssSelector("#submit"));// 检查登录按钮是否存在driver.findElement(By.cssSelector("#submit"));// 检查点击注册是否存在driver.findElement(By.cssSelector("body > div > div > div > div:nth-child(1) > div > div.text-center.text-muted.mt-3 > a"));// 检查图标是否存在driver.findElement(By.cssSelector("body > div > div > div > div:nth-child(1) > div > div.text-center.mb-4 > img"));}// 登录成功测试public void checkLoginSuccess() throws IOException {//先清空输入框 防止有信息遗留在输入框上driver.findElement(By.cssSelector("#username")).clear();driver.findElement(By.cssSelector("#password")).clear();driver.findElement(By.cssSelector("#username")).sendKeys("zhangsan");driver.findElement(By.cssSelector("#password")).sendKeys("123456");driver.findElement(By.cssSelector("#submit")).click();// 检查首页的昵称存不存 存在--登录成功 不存在 -- 登录失败driver.findElement(By.cssSelector("#index_nav_nickname"));}// 登录失败测试public void LoginFail() throws InterruptedException {//先清空输入框 防止有信息遗留在输入框上driver.findElement(By.cssSelector("#username")).clear();driver.findElement(By.cssSelector("#password")).clear();// 1. 不输入用户名driver.findElement(By.cssSelector("#username")).sendKeys("");driver.findElement(By.cssSelector("#password")).sendKeys("123456");driver.findElement(By.cssSelector("#submit")).click();// 获取请输入用户名提示String text = driver.findElement(By.cssSelector("#signInForm > div.mb-3 > div")).getText();// 要是获取的提示不正确报错assert "用户名不能为空".equals(text);// 2. 输入不存在的用户名driver.findElement(By.cssSelector("#username")).clear();driver.findElement(By.cssSelector("#password")).clear();driver.findElement(By.cssSelector("#username")).sendKeys("zhang");driver.findElement(By.cssSelector("#password")).sendKeys("123456");driver.findElement(By.cssSelector("#submit")).click();// 从提示弹窗中获取文本String text2 = getTestFromAler("/html/body/div[2]/div[1]");// 要是获取的提示不正确报错assert "用户不存在".equals(text2);// 3. 输入错误的密码driver.findElement(By.cssSelector("#username")).clear();driver.findElement(By.cssSelector("#password")).clear();driver.findElement(By.cssSelector("#username")).sendKeys("zhangsan");driver.findElement(By.cssSelector("#password")).sendKeys("666");driver.findElement(By.cssSelector("#submit")).click();// 从提示弹窗中获取文本String text3 = getTestFromAler("/html/body/div[2]/div[2]");// 要是获取的提示不正确报错assert "密码错误".equals(text3);} }
RegisterTest类:
用来自动化测试注册界面package tests; import common.Utils; import org.openqa.selenium.By; import java.util.UUID;public class RegisterTest extends Utils {// 注册界面的URLprivate static String url = "http://127.0.0.1:58080/sign-up.html";public RegisterTest() {super(url);}// 检查元素是否存在 -- 不存在就报错public void checkEleExist() {// 检查用户名输入框是否存在driver.findElement(By.cssSelector("#username"));// 检查昵称输入框是否存在driver.findElement(By.cssSelector("#nickname"));// 检查密码输入框是否存在driver.findElement(By.cssSelector("#password"));// 检查确认密码是否存在driver.findElement(By.cssSelector("#passwordRepeat"));// 检同意条款是否存在driver.findElement(By.cssSelector("#policy"));// 检查注册按钮是否存在driver.findElement(By.cssSelector("#submit"));// 检查图标是否存在driver.findElement(By.cssSelector("body > div > div > div.text-center.mb-4 > img"));}// 测试注册成功public void checkRegisterSuccess() {// 先清除输入框内容inputBoxClear();// 获取随机字符串,避免用户名重复String userName = getUserName();// 输入正确的用户名,昵称,密码与确认密码,勾选同意使用条款能否注册成功driver.findElement(By.cssSelector("#username")).sendKeys(userName);driver.findElement(By.cssSelector("#nickname")).sendKeys(userName);driver.findElement(By.cssSelector("#password")).sendKeys("123456");driver.findElement(By.cssSelector("#passwordRepeat")).sendKeys("123456");driver.findElement(By.cssSelector("#policy")).click();driver.findElement(By.cssSelector("#submit")).click();// 注册成功后会跳转登录界面 看看能不能获取到登录页面的元素String text = driver.findElement(By.cssSelector("body > div > div > div > div:nth-child(1) > div > div.card.card-md > div > h2")).getText();// 要是获取的提示不正确报错assert "用户登录".equals(text);}// 测试注册失败public void checkRegisterFail() {// 注册用户名存在的用户driver.findElement(By.cssSelector("#username")).sendKeys("zhangsan");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();driver.findElement(By.cssSelector("#submit")).click();String text = getTestFromAler("/html/body/div[2]/div[1]");// 要是获取的提示不正确报错assert "用户名已存在".equals(text);// 先清除输入框内容inputBoxClear();String userName = getUserName();// 密码与确认密码不一样driver.findElement(By.cssSelector("#username")).sendKeys(userName);driver.findElement(By.cssSelector("#nickname")).sendKeys(userName);driver.findElement(By.cssSelector("#password")).sendKeys("123456");driver.findElement(By.cssSelector("#passwordRepeat")).sendKeys("111111");driver.findElement(By.cssSelector("#submit")).click();// 打印提示框信息String text1 = driver.findElement(By.cssSelector("#signUpForm > div > div:nth-child(5) > div > div")).getText();// 要是获取的提示不正确报错assert "请检查确认密码".equals(text1);}// 用来清除注册界面输入框的内容private void inputBoxClear() {driver.findElement(By.cssSelector("#username")).clear();driver.findElement(By.cssSelector("#nickname")).clear();driver.findElement(By.cssSelector("#password")).clear();driver.findElement(By.cssSelector("#passwordRepeat")).clear();}// 获取随机用户名private String getUserName() {UUID uuid = UUID.randomUUID();String username = String.valueOf(uuid);username = username.substring(1,8);return username;} }
HomePageTest类:
用来自动化测试首页package tests; import common.Utils; import org.openqa.selenium.By; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.Keys;import java.io.IOException; public class homePageTest extends Utils {public static String url = "http://127.0.0.1:58080/index.html";public homePageTest() {super(url);}public void checkUnLogin() throws IOException {// 截图查看未登录访问首页的结果screenshot("homePage","测试未登录访问首页");}// 检查元素是否存在 -- 不存在就报错public void checkEleExist() throws IOException {// 检查首页是否显示用户昵称driver.findElement(By.cssSelector("#index_nav_nickname"));// 检查发布帖子按钮是否存在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"));// 检查首页标签是否存在driver.findElement(By.cssSelector("#article_list_board_title"));// 检查帖子是否存在driver.findElement(By.cssSelector("#artical-items-body > div:nth-child(1) > div > div.col > div.text-truncate > a > strong"));// 检查板块是否存在driver.findElement(By.cssSelector("#topBoardList > li:nth-child(2) > a > span.nav-link-title"));// 检查私信图标是否存在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"));// 截图查看首页的结果screenshot("homePage","检查首页元素");}// 测试能否成功发帖public void checkPost() throws InterruptedException {// 点击发布帖子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_title")).sendKeys("自动化测试标题");// tab键跳转到输入内容的位置driver.findElement(By.cssSelector("#article_post_title")).sendKeys(Keys.TAB);// 输入帖子内容driver.switchTo().activeElement().sendKeys("自动化测试内容");// 等待50ms到输入帖子内容Thread.sleep(50);// 由于发布帖子按钮在页面下需要使用模拟使用鼠标滚轮滚到底部((JavascriptExecutor) driver).executeScript("window.scrollTo(0, document.body.scrollHeight)");// 强制等待0.5让页面滚到底部Thread.sleep(500);// 点击发布driver.findElement(By.cssSelector("#article_post_submit")).click();// 发送成功后会跳转到首页,获取首篇帖子标题看是否一致String title = driver.findElement(By.cssSelector("#artical-items-body > div:nth-child(1) > div > div.col > div.text-truncate > a > strong")).getText();// 要是获取的提示不正确报错assert "自动化测试标题".equals(title);}// 测试没有标题能否成功发帖public void checkPostNotTitle() throws InterruptedException {// 点击发布帖子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_title"));// tab键跳转到输入内容的位置driver.findElement(By.cssSelector("#article_post_title")).sendKeys(Keys.TAB);// 输入帖子内容driver.switchTo().activeElement().sendKeys("自动化测试内容");// 等待50ms到输入帖子内容Thread.sleep(50);// 由于发布帖子按钮在页面下需要使用模拟使用鼠标滚轮滚到底部((JavascriptExecutor) driver).executeScript("window.scrollTo(0, document.body.scrollHeight)");// 强制等待0.5让页面滚到底部Thread.sleep(500);// 点击发布driver.findElement(By.cssSelector("#article_post_submit")).click();String text = getTestFromAler("/html/body/div[4]/div[1]");// 要是获取的提示不正确报错assert "请输入帖子标题".equals(text);}// 测试没有内容能否成功发帖public void checkPostNotContent() throws InterruptedException {// 点击发布帖子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_title")).sendKeys("自动化测试标题");// 由于发布帖子按钮在页面下需要使用模拟使用鼠标滚轮滚到底部((JavascriptExecutor) driver).executeScript("window.scrollTo(0, document.body.scrollHeight)");// 强制等待0.5让页面滚到底部Thread.sleep(500);// 点击发布driver.findElement(By.cssSelector("#article_post_submit")).click();String text2 = getTestFromAler("/html/body/div[4]/div[1]");// 要是获取的提示不正确报错assert "请输入帖子内容".equals(text2);}// 测试点击帖子能否跳转到帖子详情public void checkPostSkip() {// 点击帖子driver.findElement(By.cssSelector("#artical-items-body > div:nth-child(2) > div > div.col > div.text-truncate > a > strong")).click();// 每个帖子都有一个点赞按钮// 获取点赞按钮 存在 -- 成功 不存在 -- 报错driver.findElement(By.cssSelector("#details_btn_like_count"));} }
4.性能测试
使用 jmeter 对登录页面,论坛首页,帖子详情页进行梯度压力测试
配置 100 个线程,每 2s 增加 10 个线程对页面进行测试梯度压力测试
响应时间:
通过折线图可以看出随着线程数的增加系统的响应时间越来越长。
TPS(每秒事务数):
通过折线图可以看出系统的TPS随线程数的增加而增加一段时间后再一段区间波动
汇总报告:
通过汇总报告可以看出性能测试整体数据的变化
运行命令生成性能测试报告:
JMeter测试报告是⼀个全面而详细的文档,它提供了关于测试执行结果的详细信息。