ChatSpace / 聊天空间 测试报告
ChatSpace / 聊天空间 测试报告
1. 项目背景
这是一个基于 Spring Boot + WebSocket 的前后端分离聊天项目。
本项目是一款集用户登录、实时通讯、消息记录管理于一体的即时通讯类应用,由本人独立完成 UI 设计、前后端开发、接口调试及云服务器部署的全流程工作。
2. 测试目标及测试任务概述
验证网页聊天程序各个功能的完整性,以及确保每个功能下的核心模块是正确的。
3. 项目模块及实现功能
- 注册功能:实现用户账号注册,包含用户名、密码等信息校验与存储,支持账号唯一性校验,确保注册流程安全可靠。
- 登录功能:基于用户名/密码完成身份验证,通过拦截器校验登录状态,生成会话标识,实现登录态持久化与权限控制。
- 获取登录用户:基于用户名/密码完成身份验证,通过拦截器校验登录状态,生成会话标识,实现登录态持久化与权限控制。
- 获取好友列表:查询并展示当前用户的好友列表,支持按在线/离线状态筛选,为即时通讯提供联系人入口。
- 获取会话信息:拉取与指定好友的历史聊天记录,支持分页加载与最后一条消息记录,保障消息查看的连贯性与完整性。
- 消息的实施传输:基于 WebSocket 实现消息的双向实时推送,支持文本消息发送与接收,确保低延迟、高可靠的即时通讯体验。
4. 测试用例

5. 自动化测试
公共类Utils
创建下载驱动 createDriver()
屏幕截图 screenShot()
退出浏览器 quit()
package common;
import io.github.bonigarcia.wdm.WebDriverManager;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.support.ui.ExpectedConditions;
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 static WebDriverWait wait = null;
public Utils(String url){
driver = createDriver();
driver.get(url);
//显示的等待
wait = new WebDriverWait(driver, Duration.ofSeconds(3));
}
//1.创建driver对象,下载驱动
public 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) throws IOException {
//表示要转换的格式
SimpleDateFormat sim1 = new SimpleDateFormat("yyy-MM-dd");
SimpleDateFormat sim2 = new SimpleDateFormat("HH_mm_ss");
//将当前系统的时间转换为上述的格式
String dirTime = sim1.format(System.currentTimeMillis());
String fileTime = sim2.format(System.currentTimeMillis());
//截图的文件名
String fileName = "./src/test/java/images"+dirTime+"/"+str +"_"+fileTime + ".png";
File srcFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(srcFile,new File(fileName));
}
//退出
public void quit(){
driver.quit();
}
}
5.1 注册功能自动化测试
检查页面元素是否存在 checkPageRight()
成功注册 registerRight()
错误的注册 --错误的用户名,正确的密码:registerFail()
import org.openqa.selenium.support.ui.ExpectedConditions;
import java.io.IOException;
public class RegisterTest extends Utils {
public static String url = "http://60.205.7.164:8088/register.html";
public RegisterTest(){
super(url);
}
//检查页面元素是否存在
public void checkPageRight() throws IOException {
//屏幕截图
screenShot(Thread.currentThread().getStackTrace()[1].getMethodName());
String name = driver.findElement(By.cssSelector("body > div.nav")).getText();
//用户名输入框,密码输入框
driver.findElement(By.cssSelector("#username"));
driver.findElement(By.cssSelector("#password"));
//注册按钮
driver.findElement(By.cssSelector("#submit"));
assert name.equals("网页聊天");
}
//正确的注册
public void registerRight() throws InterruptedException, IOException {
//清空输入框的内容
driver.findElement(By.cssSelector("#username")).clear();
driver.findElement(By.cssSelector("#password")).clear();
driver.findElement(By.cssSelector("#username")).sendKeys("xiaohong");
driver.findElement(By.cssSelector("#password")).sendKeys("123");
//点击注册按钮
driver.findElement(By.cssSelector("#submit")).click();
//等待弹窗出现
wait.until(ExpectedConditions.alertIsPresent());
//出现弹窗
Alert alert =driver.switchTo().alert();
//确认
alert.accept();
//等待两秒,截图查看是否跳转到登录界面
Thread.sleep(2000);
screenShot(Thread.currentThread().getStackTrace()[1].getMethodName());
}
//错误的注册
public void {
//清空输入框的内容
driver.findElement(By.cssSelector("#username")).clear();
driver.findElement(By.cssSelector("#password")).clear();
//错误的用户名,和空的密码
driver.findElement(By.cssSelector("#username")).sendKeys("xiaowang");
driver.findElement(By.cssSelector("#submit")).click();
//等待弹窗出现
Alert content = wait.until(ExpectedConditions.alertIsPresent());
//获取弹窗的内容
String text = content.getText();
assert text.equals("输入的用户名或密码为空");
}
}
5.2 登录功能自动化测试
页面元素是否存在 checkPageRight()
正常登录 loginRight()
错误的登录–错误的用户名和空的密码 loginFail()
正确的用户名,错误的密码 loginFailTwo()
package cases;
import common.Utils;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.support.ui.ExpectedConditions;
import java.io.IOException;
public class LoginTest extends Utils {
public static String url = "http://60.205.7.164:8088/login.html";
public LoginTest(){
super(url);
}
//检查页面元素是否存在
public void checkPageRight() throws IOException {
//屏幕截图
screenShot(Thread.currentThread().getStackTrace()[1].getMethodName());
String name = driver.findElement(By.cssSelector("body > div.nav")).getText();
//用户名输入框,密码输入框
driver.findElement(By.cssSelector("#username"));
driver.findElement(By.cssSelector("#password"));
//登录按钮
driver.findElement(By.cssSelector("#submit"));
assert name.equals("网页聊天");
}
//正确的登录
public void loginRight() throws InterruptedException, 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("123");
//点击登录按钮
driver.findElement(By.cssSelector("#submit")).click();
//等待弹窗出现
wait.until(ExpectedConditions.alertIsPresent());
//出现弹窗
Alert alert =driver.switchTo().alert();
//确认
alert.accept();
//等待两秒,截图查看是否跳转到客户端界面
Thread.sleep(2000);
screenShot(Thread.currentThread().getStackTrace()[1].getMethodName());
}
//错误的登录
public void loginFail(){
//清空输入框的内容
driver.findElement(By.cssSelector("#username")).clear();
driver.findElement(By.cssSelector("#password")).clear();
//错误的用户名,和空的密码
driver.findElement(By.cssSelector("#username")).sendKeys("zhangsan");
driver.findElement(By.cssSelector("#submit")).click();
//等待弹窗出现
Alert content = wait.until(ExpectedConditions.alertIsPresent());
//获取弹窗的内容
String text = content.getText();
assert text.equals("当前输入的用户名或密码为空");
}
//错误的登录
public void loginFailTwo(){
//清空输入框的内容
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("1233");
driver.findElement(By.cssSelector("#submit")).click();
//等待弹窗出现
Alert content = wait.until(ExpectedConditions.alertIsPresent());
//获取弹窗的内容
String text = content.getText();
assert text.equals("登录失败!");
}
}
5.3客户端界面的测试
检查页面元素checkClient()
检查会话列表下的页面元素 是否存在checkSession()
检查好友列表下的元素是否存在checkFriend()
package cases;
import common.Utils;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import java.io.IOException;
import java.util.List;
public class ClientTest extends Utils {
public static String url ="http://60.205.7.164:8088/client.html";
public ClientTest(){
super(url);
}
//检查页面元素
public void checkClient() throws IOException, InterruptedException {
wait.until(ExpectedConditions.alertIsPresent());
Alert alert = driver.switchTo().alert();
alert.accept();
LoginTest loginTest = new LoginTest();
loginTest.loginRight();
//1.检查左侧列表上方是否显示登录用户名
String name = driver.findElement(By.cssSelector("body > div.client-container > div > div.left > div.user")).getText();
assert name.equals("zhangsan");
//2.检查搜索框是否存在
driver.findElement(By.cssSelector("body > div.client-container > div > div.left > div.search > input[type=text]"));
//3.检查会话图标,好有图标是否存在
driver.findElement(By.cssSelector("body > div.client-container > div > div.left > div.tab > div.tab-session"));
driver.findElement(By.cssSelector("body > div.client-container > div > div.left > div.tab > div.tab-friend"));
//4.检查发送按钮是否存在
driver.findElement(By.cssSelector("body > div.client-container > div > div.right > div.ctrl > button"));
}
//检查会话列表下的元素都是否存在
public void checkSession() throws IOException, InterruptedException {
wait.until(ExpectedConditions.alertIsPresent());
Alert alert = driver.switchTo().alert();
alert.accept();
LoginTest loginTest = new LoginTest();
loginTest.loginRight();
String name = driver.findElement(By.cssSelector("#session-list > li:nth-child(1) > h3")).getText().trim();
List<WebElement> ele = driver.findElements(By.cssSelector("#session-list > li:nth-child(1) > p"));
if (name.isEmpty()) {
System.out.println("没有和好友进行聊天");
} else {
System.out.println("和好友进行了聊天");
}
if (ele.isEmpty()) {
System.out.println("和好友还没有进行聊天!");
} else {
System.out.println("和好友进行了聊天!");
}
Thread.sleep(2000);
screenShot(Thread.currentThread().getStackTrace()[1].getMethodName());
}
//检查当前好友列表的元素
public void checkFriend() throws IOException, InterruptedException {
wait.until(ExpectedConditions.alertIsPresent());
Alert alert = driver.switchTo().alert();
alert.accept();
LoginTest loginTest = new LoginTest();
loginTest.loginRight();
driver.findElement(By.cssSelector("body > div.client-container > div > div.left > div.tab > div.tab-friend")).click();
String friend = driver.findElement(By.cssSelector("#friend-list > li:nth-child(1) > h4")).getText().trim();
if(friend.isEmpty()){
System.out.println("当前用户没有好友!");
}else{
System.out.println("当前用户的好友:"+friend);
}
Thread.sleep(2000);
screenShot(Thread.currentThread().getStackTrace()[1].getMethodName());
}
}
5. 4会话功能测试
当点击会话列表的图标sessionList()
当点击好友列表的图标 friendList()
当点击某个好友列表下的好友时 friendChat()
点击会话列表下的最后一个好友,进行消息发送,查看发送消息之后,是否会顶置 pinnedTest()
package cases;
import common.Utils;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import java.io.IOException;
import java.util.List;
public class ListTest extends Utils {
public static String url ="http://60.205.7.164:8088/client.html";
public ListTest(){
super(url);
}
//当点击会话列表的图标
public void sessionList() throws IOException, InterruptedException {
wait.until(ExpectedConditions.alertIsPresent());
Alert alert = driver.switchTo().alert();
alert.accept();
LoginTest loginTest = new LoginTest();
loginTest.loginRight();
//点击会话列表图标,查看是否好友列表隐藏
driver.findElement(By.cssSelector("body > div.client-container > div > div.left > div.tab > div.tab-session")).click();
//会话列表的class属于是显示状态
String session = driver.findElement(By.cssSelector("#session-list")).getAttribute("class");
String friend = driver.findElement(By.cssSelector("#friend-list")).getAttribute("class");
assert session.equals("list");
assert friend.equals("list hide");
Thread.sleep(2000);
screenShot(Thread.currentThread().getStackTrace()[1].getMethodName());
}
//当点击好友列表的图标
public void friendList() throws IOException, InterruptedException {
wait.until(ExpectedConditions.alertIsPresent());
Alert alert = driver.switchTo().alert();
alert.accept();
LoginTest loginTest = new LoginTest();
loginTest.loginRight();
//点击好友列表图标,查看是否会话列表隐藏
driver.findElement(By.cssSelector("body > div.client-container > div > div.left > div.tab > div.tab-friend")).click();
//好友列表的class属于是显示状态
String session = driver.findElement(By.cssSelector("#session-list")).getAttribute("class");
String friend = driver.findElement(By.cssSelector("#friend-list")).getAttribute("class");
assert session.equals("list hide");
assert friend.equals("list");
Thread.sleep(2000);
screenShot(Thread.currentThread().getStackTrace()[1].getMethodName());
}
//当点击某个好友列表下的好友时
public void friendChat() throws IOException, InterruptedException {
wait.until(ExpectedConditions.alertIsPresent());
Alert alert = driver.switchTo().alert();
alert.accept();
LoginTest loginTest = new LoginTest();
loginTest.loginRight();
driver.findElement(By.cssSelector("body > div.client-container > div > div.left > div.tab > div.tab-friend")).click();
List<WebElement> ele = driver.findElements(By.cssSelector("#friend-list"));
if(ele.isEmpty()){
System.out.println("当前登录用户没有好友");
}else{
String friendName = driver.findElement(By.cssSelector("#friend-list > li:nth-child(1) > h4")).getText();
driver.findElement(By.cssSelector("#friend-list > li:nth-child(1) > h4")).click();
//1.查看是否跳转到会话好友列表
String session = driver.findElement(By.cssSelector("#session-list")).getAttribute("class");
String friend = driver.findElement(By.cssSelector("#friend-list")).getAttribute("class");
assert session.equals("list");
assert friend.equals("list hide");
//2.检查会话列表第一个是不是当前点击的好友
String name = driver.findElement(By.cssSelector("#session-list > li.selected > h3")).getText();
assert name.equals(friendName);
//检查是否是被选中状态
String lable = driver.findElement(By.cssSelector("#session-list > li.selected")).getAttribute("class");
assert lable.equals("selected");
//3.检查最后一条消息是否是正确的
String messageLast =driver.findElement(By.cssSelector("#session-list > li.selected > p")).getText();
List<WebElement> message = driver.findElements(By.cssSelector(".message-show > div.message"));
if(message.isEmpty() && messageLast.isEmpty()){
System.out.println("聊天记录为空!");
}else {
int size = message.size();
String cssStr = "body > div.client-container > div > div.right > div.message-show > div:nth-child(" + size + ") > div > p";
String last = driver.findElement(By.cssSelector(cssStr)).getText().trim();
assert messageLast.equals(last);
}
//4.会话列表区的好友和消息区展示的好友是否是一样的
String chatFriend = driver.findElement(By.cssSelector("body > div.client-container > div > div.right > div.title")).getText();
assert name.equals(chatFriend);
}
}
//点击会话列表下的最后一个好友,进行消息发送,查看发送消息之后,是否会顶置
public void pinnedTest() throws IOException, InterruptedException {
wait.until(ExpectedConditions.alertIsPresent());
Alert alert = driver.switchTo().alert();
alert.accept();
LoginTest loginTest = new LoginTest();
loginTest.loginRight();
List<WebElement> unSelectedList = driver.findElements(By.cssSelector("#session-list > li:not(.selected)"));
if(unSelectedList.isEmpty()){
System.out.println("没有选中会话");
}else {
unSelectedList.get(0).click();
String state = unSelectedList.get(0).getAttribute("class");
assert state.equals("selected");
String name = unSelectedList.get(0).findElement(By.cssSelector("h3")).getText();
//在输入框输入内容
driver.findElement(By.cssSelector("body > div.client-container > div > div.right > textarea")).sendKeys("你好");
driver.findElement(By.cssSelector("body > div.client-container > div > div.right > div.ctrl > button")).click();
//查看指定的元素是否是当前的name
String chatUsername =driver.findElement(By.cssSelector("#session-list > li.selected > h3")).getText();
assert name.equals(chatUsername);
}
}
}
5.5 消息传输功能测试
成功发送消息sendSuccess()
消息发送失败—不输入内容直接发送 sendFail()
查看发送消息的左右两侧是否是正确的名称 messageTest()
消息的发送messageTrans()
package cases;
import common.Utils;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import java.io.IOException;
import java.util.List;
public class MessageTest extends Utils {
public static String url ="http://60.205.7.164:8088/client.html";
public MessageTest(){
super(url);
}
//成功发送消息
public void sendSuccess() throws IOException, InterruptedException {
wait.until(ExpectedConditions.alertIsPresent());
Alert alert = driver.switchTo().alert();
alert.accept();
LoginTest loginTest = new LoginTest();
loginTest.loginRight();
List<WebElement> unSelectedList = driver.findElements(By.cssSelector("#session-list > li:not(.selected)"));
if(unSelectedList.isEmpty()){
System.out.println("没有选中会话");
}else {
unSelectedList.get(0).click();
Thread.sleep(2000);
driver.findElement(By.cssSelector("body > div.client-container > div > div.right > textarea")).sendKeys("hello");
//点击发送
driver.findElement(By.cssSelector("body > div.client-container > div > div.right > div.ctrl > button")).click();
//选中标签是message-right的查看名称是否是好友
List<WebElement> messageRight = driver.findElements(By.cssSelector(".message-show > div.message.message-right"));
if(messageRight.isEmpty()){
System.out.println("当前登录用户发送消息失败");
}else{
int size = messageRight.size();
Thread.sleep(2000);
String content= messageRight.get(size-1).findElement(By.cssSelector(".box >p")).getText().trim();
assert content.equals("hello");
}
}
Thread.sleep(2000);
screenShot(Thread.currentThread().getStackTrace()[1].getMethodName());
}
//消息发送失败---不输入内容直接发送
public void sendFail() throws IOException, InterruptedException {
wait.until(ExpectedConditions.alertIsPresent());
Alert alert = driver.switchTo().alert();
alert.accept();
LoginTest loginTest = new LoginTest();
loginTest.loginRight();
List<WebElement> unSelectedList = driver.findElements(By.cssSelector("#session-list > li:not(.selected)"));
if(unSelectedList.isEmpty()){
System.out.println("没有选中会话");
}else {
unSelectedList.get(0).click();
Thread.sleep(2000);
//点击发送
driver.findElement(By.cssSelector("body > div.client-container > div > div.right > div.ctrl > button")).click();
}
Thread.sleep(2000);
screenShot(Thread.currentThread().getStackTrace()[1].getMethodName());
}
//查看发送消息的左右两侧是否是正确的名称
public void messageTest() throws IOException, InterruptedException {
wait.until(ExpectedConditions.alertIsPresent());
Alert alert = driver.switchTo().alert();
alert.accept();
LoginTest loginTest = new LoginTest();
loginTest.loginRight();
List<WebElement> unSelectedList = driver.findElements(By.cssSelector("#session-list > li:not(.selected)"));
if(unSelectedList.isEmpty()){
System.out.println("没有选中会话");
}else {
unSelectedList.get(0).click();
//获取到当前徐那种的好友名字
String chatFriend = unSelectedList.get(0).findElement(By.cssSelector("h3")).getText();
//选中标签是message-left的查看名称是否是好友
List<WebElement> messageLeft = driver.findElements(By.cssSelector(".message-show > div.message.message-left"));
if(messageLeft.isEmpty()){
System.out.println("好友还没有和你进行对话");
}else{
String friendName = messageLeft.get(0).findElement(By.cssSelector(".box >h4")).getText();
assert friendName.equals(chatFriend);
}
//选中标签是message-right的查看名称是否是好友
List<WebElement> messageRight = driver.findElements(By.cssSelector(".message-show > div.message.message-right"));
if(messageRight.isEmpty()){
System.out.println("当前登录用户还没有进行对话");
}else{
String friendName = messageRight.get(0).findElement(By.cssSelector(".box >h4")).getText().trim();
assert friendName.equals("zhangsan");
}
}
Thread.sleep(2000);
screenShot(Thread.currentThread().getStackTrace()[1].getMethodName());
}
//消息的发送
public void messageTrans() throws IOException, InterruptedException {
sendSuccess();
List<WebElement> unSelectedList = driver.findElements(By.cssSelector("#session-list > li:not(.selected)"));
if (unSelectedList.isEmpty()) {
System.out.println("没有选中会话");
}
String name = unSelectedList.get(0).findElement(By.cssSelector("h3")).getText().trim();
TalkTest talkTest = new TalkTest();
talkTest.login(name);
//获取好友的会话列表
Thread.sleep(2000);
String friend = driver.findElement(By.cssSelector("#session-list > li > h3")).getText();
assert friend.equals("zhangsan");
String content = driver.findElement(By.cssSelector("#session-list > li > p")).getText();
assert content.equals("hello");
//点击消息区,看最后一条是否是刚刚发送的内容
driver.findElement(By.cssSelector("#session-list > li")).click();
List<WebElement> message = driver.findElements(By.cssSelector(".message-show > div.message"));
int size = message.size();
String cssStr = "body > div.client-container > div > div.right > div.message-show > div:nth-child(" + size + ") > div > p";
String last = driver.findElement(By.cssSelector(cssStr)).getText().trim();
assert last.equals("hello");
//获取最后一条消息的class标签是否是在左边
//body > div.client-container > div > div.right > div.message-show > div:nth-child(18)
String cssStr1 = "body > div.client-container > div > div.right > div.message-show > div:nth-child("+size+")";
String lable = driver.findElement(By.cssSelector(cssStr1)).getAttribute("class");
assert lable.contains("message message-left") : "最后一条消息不是左侧,class=" + lable;
}
}
6. 接口测试

6.1获取好友列表

6.2 获取所有会话信息

6.3获取历史消息

7. 性能测试
7.1 接口性能测试
7.1.1聚合报告

7.1.2 TPS可视化

1.图标结构与描述
- 横轴 :时间(从 00:00:00 到 00:01:46 左右),反映测试的时间进程。
- 纵轴:每秒事务数(Transactions/sec),体现系统在单位时间内成功处理的请求量。
- 多色折线 :每条折线对应一个系统接口,图例标注了接口类型,如 “登录请求”“获取具体的会话历史消息”“获取好友列表” 等,且均标注为 (success),表示统计的是成功请求的吞吐量。
2.图标结构与描述
-
启动阶段(00:00:00 - 00:00:10):各接口的每秒事务数快速攀升,在约 10 秒时达到峰值(接近 90 次 / 秒),说明系统在压测启动后迅速进入高负载状态,成功处理了大量并发请求。
-
稳定阶段(00:00:10 - 00:01:35):吞吐量在 60-70 次 / 秒的区间内小幅波动,整体保持平稳,表明系统在持续负载下能够稳定处理请求,吞吐量未出现明显衰减。
-
结束阶段(00:01:35 之后):所有接口的每秒事务数急剧下降至接近 0,这是压测结束、并发线程停止的正常表现,而非系统性能问题。
7. 1.3响应时间可视化

1.图标结构与描述
- 横轴 :时间(从 00:00:00 到 00:01:46 左右),反映测试的时间进程。
- 纵轴:响应时间(单位 ms),体现接口处理请求的耗时。
- 多色折线 :每条折线对应一个系统接口,图例标注了接口类型,如 “登录请求”“获取具体的会话历史消息”“获取好友列表” 等。
2.性能趋势分析
-
平稳阶段(00:00:00 - 00:01:35):除 “获取具体的会话历史消息” 外,其他接口(登录请求、获取好友列表等)的响应时间始终保持在极低水平,曲线几乎贴近横轴,说明在压测的大部分时间里,这些接口性能稳定,响应迅速。
-
拐点阶段(00:01:35 之后):“获取具体的会话历史消息” 接口的响应时间出现了急剧飙升,从接近 0ms 直接飙升至近 60000ms(即 60 秒),这是一个非常明显的性能拐点。
7.1.4性能测试报告

1.接口差异
- 获取好友列表:APDX最高,性能最优。
- “获取会话历史消息”:APDX最低的,是相对处于短板。
2.请求与错误统计
-
请求成功率:所有接口请求成功率为100%,无任务失败请求,系统稳定性较佳。
-
总样本量:共执行 31792 次请求,覆盖充分,压测结果可靠。
- 短板:“获取具体的会话历史消息” 的最大响应时间达到 29143ms(约 29 秒),存在极端长尾请求,是主要性能瓶颈。
- 问题原因推测:
- 1.该接口可能涉及大量历史消息的数据库查询,且未建立有效索引,导致在高并发下查询效率极低。
2.也可能是消息存储未做分页或缓存,一次性加载过多数据,导致内存和 IO 资源耗尽。 - 优化 :对消息表建立合理的索引; 实现消息分页加载,避免一次性返回太多数据;引入redis缓存,缓存用户最近的历史消息,减少数据库的压力。
7.2Websocket消息发送接收性能测试
7.2.1 聚合报告

7.2.2 TPS可视化

1.图标结构与描述
- 横轴 :时间(从 00:00:00 到 00:01:46 左右),反映测试的时间进程。
- 纵轴:每秒事务数(Transactions/sec),体现系统在单位时间内成功处理的请求量。
- 多色折线 :每条折线对应一个系统接口,图例标注了操作类型,如 “登录请求”“WebSocket 连接”“WebSocket 发送消息”“WebSocket 接收消息”“WebSocket Close”,且均标注为 (success),表示统计的是成功请求的吞吐量。
2.性能趋势分析
- 启动阶段(00:00:00 - 00:00:10):各操作的每秒事务数快速攀升,在约 10 秒时达到峰值(接近 20 次 / 秒),说明系统在压测启动后迅速进入高负载状态,成功处理了大量并发请求。
- 稳定阶段(00:00:10 - 00:01:20):吞吐量在 2-12 次 / 秒的区间内小幅波动,整体保持平稳,表明系统在持续负载下能够稳定处理请求,吞吐量未出现明显衰减。
- 结束阶段(00:01:20 之后):所有操作的每秒事务数急剧下降至接近 0,这是压测结束、并发线程停止的正常表现,而非系统性能问题。
吞吐量表现稳定:各操作的吞吐量曲线高度同步,说明压测场景下的请求分布均匀,系统对不同操作的处理能力均衡。
7.2.3 响应时间可视化

1.图标结构与描述
- 横轴 :时间(从 00:00:00 到 00:01:28 左右),反映测试的时间进程。
- 纵轴:响应时间(单位 ms),体现接口处理请求的耗时。
2.性能趋势分析
- WebSocket 接收消息(青色):响应时间始终稳定在约 3000ms(3 秒),曲线几乎是一条直线,说明该操作的延迟是持续且固定的,是整个系统最严重的性能瓶颈。
- WebSocket 发送消息(绿色):
响应时间始终接近 0ms,表现极为优异,满足即时通讯场景下的低延迟需求。 - WebSocket Close(深棕色):
响应时间始终稳定在 0-100ms 之间,表现平稳,无明显波动。 - 登录请求(红色)与 WebSocket 连接(紫色):
前期(00:00:00 - 00:00:45):响应时间稳定在 0-300ms,表现良好。
后期(00:00:45 之后):响应时间出现剧烈波动,峰值可达 1000ms 以上,甚至接近 1200ms,说明在持续负载下,登录和连接操作的性能出现了明显衰减。
3.结论
- 发送性能突出:WebSocket 发送消息几乎无耗时,性能表现完美。
- 接收性能瓶颈:WebSocket 接收消息的响应时间固定在 3 秒,严重影响用户体验,是最核心的性能短板。
- 后期性能衰减:登录请求和 WebSocket 连接在压测后期出现明显的响应时间波动和峰值,说明系统在持续高负载下的稳定性不足。
- 关闭操作稳定:WebSocket Close 操作始终表现平稳,无性能问题。
4.优化建议
1.WebSocket 接收消息优化:
- 检查服务端消息推送逻辑,避免在接收消息时执行同步的数据库查询或其他耗时操作。
- 引入消息队列(进行异步处理,降低同步阻塞 )优化客户端消息处理逻辑,避免在主线程中处理大量消息。
2.登录与连接优化:
- 调整服务端线程池和连接池配置,避免资源耗尽导致超时。
- 对登录态和连接信息进行缓存,减少重复认证和连接建立的开销。
7.2.4 性能测试报告

1.请求与错误统计
1.WebSocket 接收消息优化:
-
请求成功率:整体请求成功率为 99.92%,仅出现 1 次失败,系统稳定性极佳。
-
错误详情:唯一的错误是 “登录请求” 接口的连接超时(Connection timed out),属于偶发的网络或服务端负载问题,而非系统性缺陷。
2.存在短板:
- WebSocket 接收消息是最严重的性能瓶颈,平均响应时间高达 3007.11ms(约 3 秒),且所有百分位均在 3000ms 以上,说明延迟是持续存在的。
3.优化:
- 服务端优化:检查 WebSocket 服务端的消息推送逻辑,避免在接收消息时进行耗时操作(如数据库查询),引入消息队列异步处理。
- 连接池优化:调整 WebSocket 连接池和登录服务的线程池配置,避免连接数过多导致的资源竞争和超时。
- 缓存策略:对登录态和连接信息进行缓存,减少重复认证和连接建立的开销。
8. 兼容性测试
场景一:Chrome浏览器测试


场景二:edge浏览器测试

9. 安全测试
未登录状态下,是否可以进行客户端界面的访问?
结果 不可以进行访问的

10. 网络测试
有网络下可以正常访问:
无网络不能正常访问:
11 . 测试总结
1. 自动化测试:
针对注册、登录、客户端界面、会话功能、消息传输等核心模块,设计了完整的自动化测试用例,覆盖页面元素校验、功能流程验证和异常场景测试。
- 注册功能:通过 checkPageRight() 检查页面元素,registerRight() 验证正常注册流程,registerFail() 覆盖错误用户名 + 正确密码等异常场景。
- 登录功能:通过 checkPageRight() 检查页面元素,loginRight() 验证正常登录,loginFail()/loginFailTwo() 覆盖错误用户名、空密码、正确用户名 + 错误密码等异常场景。
- 客户端界面:通过 checkClient() 检查客户端整体元素,checkSession() 验证会话列表元素,checkFriend() 验证好友列表元素,保障界面展示正确性。
- 会话功能:通过 sessionList() 验证会话列表点击,friendList() 验证好友列表点击,friendChat() 验证好友聊天入口,pinnedTest() 验证消息发送后会话置顶功能。
- 消息传输功能:通过 sendSuccess() 验证正常消息发送,sendFail() 覆盖空内容发送失败场景,messageTest() 校验消息发送者 / 接收者名称展示,messageTrans() 验证消息传输流程。
2.接口测试:
针对登录、获取登录用户信息,好友列表,获取会话信息,历史消息等接口,通过率95%,发现并修复接口逻辑漏洞 3处。
3.性能测试:
针对接口性能测试:
所有接口的 APDEX 评分都在 0.960 以上,整体为 0.987,说明在大部分时间里用户体验优秀。
阈值(T)为 500ms,而 “获取具体的会话历史消息” 的最大响应时间远超阈值,导致其 APDEX 相对最低(0.960),是影响用户体验的主要环节。
4.兼容性测试:
无论是在联想浏览器,edge浏览器,还是谷歌浏览器,打开的页面效果均无遮挡,界面布局,交互体验是一致的。不同环境下均可运行。
总结:网页聊天程序的基本功能是可以正常运行的,流程能够正确执行。需要优化:在高并发下查询历史消息的效率极低,可以引入redis缓存进行缓解。交互体验良好:所有页面内容均能正常显示,无错别字,遮挡,异常。
更多推荐



所有评论(0)