一、项目背景
1.1 测试目标及测试任务
测试目标旨在保障功能无漏洞、流程顺畅,实现多端显示交互一致,达成高并发场景下响应时间<2 秒等性能指标,抵御 SQL 注入等安全攻击,提升 UI 易用性与提示友好度;
背景任务源于系统功能的复杂性(需验证用户注册登录、帖子发布评论等核心功能逻辑及多角色权限控制)性能稳定性压力(高并发下响应速度与资源利用率优化)。
1.2 项目技术栈
后端:Spring Boot/Spring MVC/WebSocket
数据库:MySQL
前端:原生HTML/CSS
1.3 测试时间
2025.06 - 2025.06
1.4 项目简介
基于Spring前后端分离的论坛系统,实现了注册、登录、显示帖子、编辑帖子、删除帖子、回复帖子、点赞帖子,修改个人信息等功能,并将其部署到云服务器上。
1.5. 测试环境
类别 | 配置/版本 |
硬件 | HP EliteBook 845 |
自动化测试浏览器 | Google Chrome 137.0.7151.119 |
自动化测试工具 | Selenium 4.21.0 |
手动测试浏览器 | Microsoft Edge 137.0.3296.83 |
操作系统 | Windows 11 家庭中文版 |
开发工具 | IntelliJ IDEA 2022.1.4 |
性能测试工具 | jmeter 5.5 |
二、测试分类
2.1 测试描述
2.1.1 功能测试(Functional Testing)
验证系统功能是否符合需求规格,覆盖核心业务逻辑:
用户模块:注册 / 登录(验证码、密码强度)、账号激活 / 注销、个人信息修改、头像上传等。
内容模块:帖子发布(文字 / 图片 / 视频)、评论 / 回复、点赞 / 收藏、帖子编辑 / 删除、精华帖 / 置顶管理。
板块模块:板块创建 / 删除、分类管理、版主权限分配、帖子移动 / 归档。
2.1.2兼容性测试(Compatibility Testing)
确保系统在不同环境下正常运行:
浏览器兼容:Chrome、Firefox、Edge、Safari 的页面渲染、JS 交互一致性。
设备兼容:iOS(iPhone/iPad)、Android(不同品牌机型)的移动端适配,屏幕尺寸 / 分辨率适配。
操作系统:Windows、macOS、Linux 的服务端兼容性(若涉及客户端)。
版本兼容:旧版本浏览器 / 系统的降级支持(如有必要)。
2.1.3性能测试(Performance Testing)
评估系统在压力下的稳定性与效率:
负载测试:模拟逐步增加用户并发量(如 100/500/1000 人同时在线),监测响应时间、吞吐量、错误率。
压力测试:超预期负载下(如 2000 并发),测试系统崩溃临界点,优化数据库连接池、缓存机制。
稳定性测试:持续高负载运行 24 小时以上,验证内存泄漏、资源释放是否正常。
大数据测试:模拟百万级帖子 / 评论数据,测试查询、分页、统计功能的性能衰减情况。
2.1.4 安全性测试(Security Testing)
识别并修复潜在安全风险:
身份验证:测试密码强度、找回机制(防止暴力破解)、Session 过期时间、Token 安全(JWT 等)。
数据安全:敏感信息加密(用户密码、手机号)、传输层加密(HTTPS)、数据库权限隔离。
漏洞扫描:检测 SQL 注入
权限越界:验证用户是否能通过 URL 篡改访问未授权页面(如直接访问管理员后台)。
内容安全:敏感词过滤(政治 / 色情词汇)、图片 / 视频违规内容识别(需结合 AI 审核)。
2.1.5 界面测试(Usability Testing)
优化用户体验与操作便捷性:
界面测试:布局合理性(如按钮位置、信息层级)、视觉一致性(配色 / 字体)、移动端手势适配(滑动 / 缩放)。
交互测试:操作流程是否符合用户习惯(如发帖需先选择板块)、错误提示清晰度(如 “网络连接失败”)。
无障碍测试:屏幕阅读器支持(如适配 VoiceOver)、键盘导航可用性(Tab 键切换焦点)。
用户反馈:通过真实用户调研,收集对功能入口、操作复杂度的改进建议。
2.1.6 易用性测试(Usability Testing)
界面直观性:用户能否快速识别核心功能(如发帖、搜索)。
操作便捷性:完成常见任务(如注册、评论)的步骤是否简洁。
容错性:用户误操作时是否有补救措施(如撤销删除)。
信息可读性:文字排版、图标含义是否易于理解。
2.2 功能测试
2.2.1测试用例设计
注册
登录
论坛主页面
论坛发帖页面
帖子详情页面
2.3手动测试
注册
注册失败
注册成功直接跳转登录
登录
登录失败
登录成功后进入论坛主页面
论坛主页面
切换窗口
搜索框输入
切换夜间模式
查看站内私信
论坛发帖页面
编辑帖子
发帖成功
帖子详情页面
查看帖子
查看回复
回复帖子评论
点赞帖子
给用户发私信
2.4 自动化测试
注册
页面注册成功
//检查注册页面加载成功public void SignUpRight()throws InterruptedException, IOException {//通过查看页面元素是否存在来检查加载成功与否driver.findElement(By.cssSelector("body > div > div > div.text-center.text-muted.mt-3"));//注册输入框driver.findElement(By.cssSelector("#submit"));}
//检查注册功能--成功注册public void SignUpSuc() {driver.findElement(By.cssSelector("#username")).sendKeys("forward333210");driver.findElement(By.cssSelector("#nickname")).sendKeys("roy");driver.findElement(By.cssSelector("#password")).sendKeys("kml123456");driver.findElement(By.cssSelector("#passwordRepeat")).sendKeys("kml123456");driver.findElement(By.xpath("//*[@id=\"policy\"]")).click();driver.findElement(By.cssSelector("#submit")).click();//检查点击注册之后是否注册成功driver.findElement(By.cssSelector("#submit"));//页面标题来检查是否注册成功String expect = driver.getTitle();assert expect.equals("比特论坛 - 用户登录");driver.quit();}
页面注册失败
//检查注册失败public void SignUpFail() throws InterruptedException {//通过clear保证输入框没有文本// driver.findElement(By.cssSelector("username")).clear();// driver.findElement(By.cssSelector("#nickname")).clear();// driver.findElement(By.cssSelector("#password")).clear();//刷新文本driver.navigate().refresh();driver.findElement(By.cssSelector("#username")).sendKeys("forward333210");driver.findElement(By.cssSelector("#nickname")).sendKeys("roy");driver.findElement(By.cssSelector("#password")).sendKeys("kml123456");// driver.findElement(By.cssSelector("#passwordRepeat")).sendKeys("kml123456");driver.findElement(By.xpath("//*[@id=\"policy\"]")).click();driver.findElement(By.cssSelector("#submit")).click();Thread.sleep(1000);//通过再次确实密码验证注册失败driver.findElement(By.cssSelector("#signUpForm > div > div:nth-child(5) > div > div"));driver.quit();}
登录
登录成功
public void SignInRight() throws InterruptedException {//通过查看页面元素是否存在来检查加载成功与否driver.findElement(By.cssSelector("body > div > div > div > div:nth-child(1) > div > div.card.card-md > div > h2"));//登录输入框driver.findElement(By.cssSelector("#submit"));}//检查登录功能--成功登录public void SignInSuc() throws InterruptedException {driver.findElement(By.cssSelector("#username")).sendKeys("forward");driver.findElement(By.cssSelector("#password")).sendKeys("kml123456");driver.findElement(By.cssSelector("#submit")).click();//检查点击登录之后是否登录成功driver.findElement(By.cssSelector("#article_list_board_title"));//页面标题来检查是否登录成功String expect = driver.getTitle();assert expect.equals("比特论坛");Thread.sleep(3000);driver.quit();}
登录失败
public void SignInFail() throws InterruptedException, IOException {//账号为空driver.navigate().refresh();driver.findElement(By.cssSelector("#username")).sendKeys("");driver.findElement(By.cssSelector("#password")).sendKeys("kml123456");//显示密码driver.findElement(By.cssSelector("#password_a > svg")).click();driver.findElement(By.cssSelector("#submit")).click();//通过再次确实账号为空验证登录失败driver.findElement(By.cssSelector("#signInForm > div.mb-3 > div"));//密码为空driver.navigate().refresh();driver.findElement(By.cssSelector("#username")).sendKeys("forward");driver.findElement(By.cssSelector("#password")).sendKeys("");driver.findElement(By.cssSelector("#submit")).click();//通过再次确实密码为空验证登录失败driver.findElement(By.cssSelector("#signInForm > div.mb-2 > div > div"));//账号密码都为空driver.navigate().refresh();driver.findElement(By.cssSelector("#username")).sendKeys("");driver.findElement(By.cssSelector("#password")).sendKeys("");driver.findElement(By.cssSelector("#submit")).click();Thread.sleep(3000);driver.findElement(By.cssSelector("#signInForm > div.mb-3 > div"));driver.findElement(By.cssSelector("#signInForm > div.mb-2 > div > div"));driver.quit();}
}
论坛主页面
页面正常加载
//检查论坛主页面加载成功 需要先登录public void IndexPage()throws InterruptedException, IOException {driver.findElement(By.cssSelector("#username")).sendKeys("forward");driver.findElement(By.cssSelector("#password")).sendKeys("kml123456");driver.findElement(By.cssSelector("#submit")).click();//通过查看页面元素是否存在来检查论坛主页面加载成功driver.findElement(By.cssSelector("#nav_board_index > a"));//页面标题来检查是否论坛主页面加载成功String expect = driver.getTitle();assert expect.equals("比特论坛");Utils.getScreenShot(getClass().getName());}
屏幕截图
搜索功能正常使用
public void SearchBox() throws InterruptedException, IOException {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("12");Thread.sleep(1000);String SS=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")).getAttribute("value");assert SS.equals("12");getScreenShot(getClass().getName());driver.quit();}
屏幕截图
切换夜间/日间模式
//切换白天模式public void NightMode() throws IOException, InterruptedException {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();Thread.sleep(3000);// getScreenShot(getClass().getName());driver.quit();}
切换窗口
//切换到其他窗口public void Switchwindow() throws InterruptedException, IOException {{driver.findElement(By.cssSelector("#topBoardList > li:nth-child(2) > a > span.nav-link-title")).click();driver.findElement(By.cssSelector("#article_list_board_title"));}}}
查看站内信息
//查看站内消息public void PersonMessage() throws InterruptedException, IOException {{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")).click();driver.findElement(By.cssSelector(" #index_div_message_list > div")).click();}}
查看帖子
public void PublishPost() throws InterruptedException, IOException {driver.findElement(By.cssSelector("#artical-items-body > div:nth-child(1) > div > div.col > div.text-truncate > a > strong")).click();//getScreenShot(getClass().getName());}
点赞帖子
public void Thumbsup() throws InterruptedException, IOException {Thread.sleep(2000);driver.findElement(By.cssSelector("#artical-items-body > div:nth-child(10) > div > div.col > div.text-truncate > a > strong")).click();driver.findElement(By.cssSelector("#details_btn_like_count")).click();Thread.sleep(2000);String a =driver.findElement(By.cssSelector("body > div.jq-toast-wrap.bottom-right > div")).getText();System.out.println("打印的内容是:"+a);assert a.equals("×\n" +"成功\n" +"点赞成功");getScreenShot(getClass().getName());}
屏幕截图
论坛发帖页面
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 EditPage extends Utils {public static String url ="http://127.0.0.1:58080/index.html";public EditPage() {super(url);}public void EditPage() throws InterruptedException, IOException {driver.findElement(By.cssSelector("#username")).sendKeys("forward");driver.findElement(By.cssSelector("#password")).sendKeys("kml123456");driver.findElement(By.cssSelector("#submit")).click();Thread.sleep(3000);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();// Utils.getScreenShot(getClass().getName());//通过查看页面元素是否存在来检查发帖页面加载成功driver.findElement(By.cssSelector("#bit-forum-content > div.page-header.d-print-none > div > div > div > h2"));//页面文本信息来检查发帖页面加载成功// String except= driver.findElement(By.cssSelector("#bit-forum-content > div.page-header.d-print-none > div > div > div > h2")).getText();//System.out.println("打印的内容是:"+except);//assert except.equals("发新贴");// Utils.getScreenShot(getClass().getName());}//发帖成功public void EditSuc () throws InterruptedException {driver.findElement(By.cssSelector("#article_post_title")).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 actions = new Actions(driver);actions.click(ele).perform();Thread.sleep(3000);actions.moveToElement(ele).sendKeys("变量的定义").perform();Thread.sleep(3000);WebElement ele2 = driver.findElement(By.cssSelector("#article_post_submit"));actions.click(ele2).perform();}
//发帖失败public void EditFail() throws IOException, InterruptedException {/* driver.findElement(By.cssSelector("#article_post_title")).click();//页面标题为空WebElement ele = driver.findElement(By.cssSelector("#article_post_submit"));Actions actions = new Actions(driver);actions.click(ele).perform();driver.findElement(By.cssSelector("body > div.jq-toast-wrap.bottom-right > div"));Utils.getScreenShot(getClass().getName());*///内容为空driver.findElement(By.cssSelector("#article_post_title")).click();Thread.sleep(3000);driver.findElement(By.cssSelector("#article_post_title")).sendKeys("变量");Actions actions = new Actions(driver);Thread.sleep(3000);WebElement ele3 = driver.findElement(By.cssSelector("#article_post_submit"));actions.click(ele3).perform();Utils.getScreenShot(getClass().getName());}}
发帖成功
发帖失败
标题为空
内容为空
帖子详情页面
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 EditPage extends Utils {public static String url ="http://127.0.0.1:58080/index.html";public EditPage() {super(url);}public void EditPage() throws InterruptedException, IOException {driver.findElement(By.cssSelector("#username")).sendKeys("forward");driver.findElement(By.cssSelector("#password")).sendKeys("kml123456");driver.findElement(By.cssSelector("#submit")).click();Thread.sleep(3000);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();// Utils.getScreenShot(getClass().getName());//通过查看页面元素是否存在来检查发帖页面加载成功driver.findElement(By.cssSelector("#bit-forum-content > div.page-header.d-print-none > div > div > div > h2"));//页面文本信息来检查发帖页面加载成功// String except= driver.findElement(By.cssSelector("#bit-forum-content > div.page-header.d-print-none > div > div > div > h2")).getText();//System.out.println("打印的内容是:"+except);//assert except.equals("发新贴");// Utils.getScreenShot(getClass().getName());}//发帖成功public void EditSuc () throws InterruptedException {driver.findElement(By.cssSelector("#article_post_title")).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 actions = new Actions(driver);actions.click(ele).perform();Thread.sleep(3000);actions.moveToElement(ele).sendKeys("变量的定义").perform();Thread.sleep(3000);WebElement ele2 = driver.findElement(By.cssSelector("#article_post_submit"));actions.click(ele2).perform();}
//发帖失败public void EditFail() throws IOException, InterruptedException {/* driver.findElement(By.cssSelector("#article_post_title")).click();//页面标题为空WebElement ele = driver.findElement(By.cssSelector("#article_post_submit"));Actions actions = new Actions(driver);actions.click(ele).perform();driver.findElement(By.cssSelector("body > div.jq-toast-wrap.bottom-right > div"));Utils.getScreenShot(getClass().getName());*///内容为空driver.findElement(By.cssSelector("#article_post_title")).click();Thread.sleep(3000);driver.findElement(By.cssSelector("#article_post_title")).sendKeys("变量");Actions actions = new Actions(driver);Thread.sleep(3000);WebElement ele3 = driver.findElement(By.cssSelector("#article_post_submit"));actions.click(ele3).perform();Utils.getScreenShot(getClass().getName());}}
修改标题
回复帖子
package tests;import common.Utils;
import org.openqa.selenium.By;import java.io.IOException;public class PersonPage extends Utils {public static String url = "http://127.0.0.1:58080/index.html";public PersonPage() {super(url);}//个人中心页面加载成功public void PersonPage() throws InterruptedException, IOException {driver.findElement(By.cssSelector("#username")).sendKeys("forward");driver.findElement(By.cssSelector("#password")).sendKeys("roy123456");//修改密码后需要再次修改driver.findElement(By.cssSelector("#submit")).click();Thread.sleep(2000);driver.findElement(By.cssSelector("#index_nav_avatar")).click();driver.findElement(By.cssSelector(" #index_user_settings")).click();Thread.sleep(3000);//通过查看页面元素是否存在driver.findElement(By.cssSelector("#bit-forum-content > div.page-header.d-print-none > div > div > div > h2"));}//修改昵称public void namePage() throws InterruptedException, IOException {driver.findElement(By.cssSelector("#setting_input_nickname")).clear();Thread.sleep(2000);driver.findElement(By.cssSelector("#setting_input_nickname")).sendKeys("roylan");Thread.sleep(2000);driver.findElement(By.cssSelector("#setting_submit_nickname")).click();}//修改邮件public void EailPage() throws InterruptedException, IOException {driver.findElement(By.cssSelector("#setting_input_email")).clear();Thread.sleep(2000);driver.findElement(By.cssSelector("#setting_input_email")).sendKeys("3259215@qq.com");Thread.sleep(2000);driver.findElement(By.cssSelector("#setting_submit_email")).click();}//修改电话public void phoneNumPage() throws InterruptedException, IOException {driver.findElement(By.cssSelector("#setting_input_phoneNum")).clear();Thread.sleep(2000);driver.findElement(By.cssSelector("#setting_input_phoneNum")).sendKeys("123259215");Thread.sleep(2000);driver.findElement(By.cssSelector("#setting_submit_phoneNum")).click();}//修改密码public void PassWordPage() throws InterruptedException, IOException {driver.findElement(By.cssSelector("#settings_input_oldPassword")).sendKeys("kml123456");Thread.sleep(2000);driver.findElement(By.cssSelector("#settings_input_newPassword")).sendKeys("roy123456");Thread.sleep(2000);driver.findElement(By.cssSelector("#settings_input_passwordRepeat")).sendKeys("roy123456");Thread.sleep(2000);driver.findElement(By.cssSelector("#settings_submit_password")).click();}//修改个人简介public void RemarkPage() throws InterruptedException, IOException {driver.findElement(By.cssSelector("#settings_textarea_remark")).clear();Thread.sleep(2000);driver.findElement(By.cssSelector("#settings_textarea_remark")).sendKeys("喜欢学习测试课程");Thread.sleep(2000);driver.findElement(By.cssSelector("#settings_submit_remark")).click();}}
修改昵称
修改邮箱
修改电话
修改个人简介
2.5性能测试
线程组设计
生成聚合报告
梯度压力测试
响应时间
TPS
活跃线程数
测试报告
报告整体分析
测试用例:9
高频接口覆盖率:98%
软件:Apache JMeter 5.5
通过率:100%
测试时间:2025.6.22
结果分析:系统全程无异常
吞吐量 622.9/sec,支持高并发;
平均响应时间 26.87ms;,用户注册接口在00:00:58出现峰值(168ms);
TPS峰值 73,高负载下稳定
性能瓶颈
用户注册接口响应时间波动较大,需优先优化
2.6接口测试
http://127.0.0.1:58080/swagger-ui/index.html
三.测试结论与建议
3.1需求覆盖性
核心功能已基本实现,但部分需求细节(如密码复杂度校验、分页查询)未完全覆盖。
接口覆盖率与功能覆盖率分别达到 100% 和 95%,满足核心场景需求。
测试通过率:
接口测试、功能测试、自动化测试、性能测试通过率均为 100%,未发现功能性缺陷。
性能表现:
高并发下系统稳定性良好,TPS 表现优异,但用户注册接口存在潜在性能瓶颈(响应时间波动)。
主要缺陷:
安全性:用户注册缺乏密码复杂度校验与验证码功能。
用户体验:帖子搜索未支持精准查询,批量操作交互未优化;帖子不支持预览;无法上传修改头像
3.2 通过项
功能实现:
用户注册/登录、发布帖子、点赞回复、私信等功能均符合预期。
接口质量:
接口全部通过测试,逻辑正确且数据交互稳定。
自动化与性能基准:
自动化测试用例执行结果与预期一致,性能测试 TPS 满足高负载场景需求。
3.3 风险项
安全风险:
高优先级:密码未强制复杂度规则(如长度、特殊字符),易导致弱密码漏洞。
中优先级:注册流程无验证码,存在暴力破解或自动化注册风险。
性能风险:
登录接口响应时间波动可能影响高并发场景用户体验。
用户体验风险:
帖子搜索未精确,数据量大时页面加载缓慢。
不支持预览,易误删数据。
3.4 上线建议
优化项:帖子管理模块批量操作增加二次确认弹窗,防止误操作。
性能调优:
对用户注册接口进行性能分析(如 SQL 查询优化、缓存机制)。
上线评估:
核心功能稳定且通过全量测试,主功能测试通过,风险可控,建议按计划上线