网络聊天室测试报告

一.项目背景

这是一个基于Spring+前后端分离的网络聊天室项目 ,是一款集用户管理、信息同步发送于一体的简单聊天类应用

1.项目介绍

模块设计

  • 用户模块:实现用户登录、注册基本功能,保障用户身份管理与信息安全

  • 会话模块:支持会话添加、管理、列表展示及发送消息互动,满足用户的互动需求。

  • 好友列表功能:实现管理好友功能,便于查找好友进行聊天

  • 搜索功能:支持向指定用户添加好友,让用户"找得到、加得准、用得顺"

  • **发送消息:**用websocket同步进行消息发送,实时更新最新状态

模拟服务器有效地将消息推送到客户端(或浏览器)

技术栈

**•**后端:基于 Spring Boot + Spring MVC 构建服务端逻辑,以 MySQL 作为数据存储引擎,保障系统稳定性与数据可靠性。

**•**前端:通过简单的html实现响应式页面布局,结合 jQuery 完成 DOM 操作与 AJAX 异步请求,确保前端交互体验流畅直观

2.技术应用

  • 后端:Spring,Spring Boot,Spring MVC,MyBatis

  • 数据库:MySQL

  • 前端:HTML,CSS,JavaScript,jQuery3

• 采用统一返回格式 + 全局错误信息定义,实现前后端交互结果的标准化、一致性处理,提升接口可读性与稳定性

• 通过 @ControllerAdvice + @ExceptionHandler 注解组合,构建全局异常处理机制,统一拦截、规范化异常响应

• 利用拦截器技术实现用户登录状态校验,精准拦截未授权请求,强化系统权限管理与操作安全性

• 采用jwt令牌进行身份验证,使用无状态token进行身份校验,避免了session占用服务器资源以及CSRF攻击

二.项目模块及其实现功能

1.模块功能

1>.注册模块

2>.登陆模块

3>.板块模块

• 标签之间的切换及其获取对应的信息

(eg:点击会话加载会话列表、点击好友加载对应的好友列表、点击好友申请加载申请列表)

• 实现滑动切换标签的交互,提升操作流畅度

4>.添加好友模块

• 输入搜索内容,获取对应的好友信息

• 展示搜索结果列表,包含用户头像、昵称、个性签名等基础信息

• 在好友申请点击加载内容,进行同意好友、拒绝好友实现

5>:发送信息

2.测试用例

三.编写自动化测试完成功能测试

1.包的结构与公共代码(Common)


java 复制代码
package chatroom.Common;

import chatroom.Exception.TestException;
import chatroom.TestApi.Utils.Utils;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.List;

public class Common {

    /**
     * 会话页面
     */
    public static void SessionNorDisplay(WebDriver driver){
        System.out.println("------------------------------------------------");
        // 点击一下会话标签
        driver.findElement(By.cssSelector("body > div.client-container > div > div.left > div.tab > div.tab-session")).click();
        // 获取里面的li标签
        WebElement sessionList = driver.findElement(By.cssSelector("#session-list"));
        List<WebElement> li = sessionList.findElements(By.tagName("li"));
        if(li.size() > 0){
            // 此时随便看一下元素显示
            String text = li.get(0).findElement(By.cssSelector("h3")).getText();
            System.out.println("会话框第一个名称>:"+text);
        }else if(li.size() == 0){
            // 看一下元素
            String h3 = sessionList.findElement(By.cssSelector("h3")).getText();
            assert h3.equals("当前没有聊天记录") : "会话框没有添加好友时描述错误,"+h3;
        }else throw new TestException("会话页面显示错误");
        System.out.println("会话框元素显示正常");
    }

    /**
     * 好有列表页面
     */
    public static void FriendListNorDisplay(WebDriver driver){
        System.out.println("------------------------------------------------");
        // 点击一下好友列表
        driver.findElement(By.cssSelector("body > div.client-container > div > div.left > div.tab > div.tab-friend")).click();
        // 获取里面的li标签
        WebElement sessionList = driver.findElement(By.cssSelector("#friend-list"));
        List<WebElement> li = sessionList.findElements(By.tagName("li"));
        if(li.size() > 0){
            // 此时随便看一下元素显示
            String text = li.get(0).findElement(By.cssSelector("h4")).getText();
            System.out.println("好友列表第一个名称>:"+text);
        }else if(li.size() == 0){
            // 看一下元素
            String h3 = sessionList.findElement(By.cssSelector("h3")).getText();
            assert h3.equals("当前没有好友,请添加好友") : "好友列表没有添加好友时描述错误,"+h3;
        }else throw new TestException("好友列表页面显示错误");
        System.out.println("好友列表元素显示正常");
    }

    /**
     * 好友申请页面
     */
    public static void ApplyNorDisplay(WebDriver driver){
        System.out.println("------------------------------------------------");
        // 点击一下好友申请标签
        driver.findElement(By.cssSelector("body > div.client-container > div > div.left > div.tab > div.tab-request")).click();
        // 获取里面的li标签
        WebElement sessionList = driver.findElement(By.cssSelector("#add_firend_list"));
        List<WebElement> li = sessionList.findElements(By.tagName("li"));

        if(li.size() > 0){
            // 此时随便看一下元素显示
            String content = li.get(0).findElement(By.cssSelector("#friend_left > h3")).getText().trim();
            String text = content.split(" ")[0];
            System.out.println("好友申请第一个名称?:"+text);
        }else if(li.size() == 0){
            // 看一下元素
            String h3 = sessionList.findElement(By.cssSelector("h3")).getText();
            assert h3.equals("当前没有好友请求") : "好求请求描述错误,"+h3;
        }else throw new TestException("好友请求页面显示错误");
        System.out.println("好友申请元素显示正常");
    }

    /**
     * 全屏截图
     * @param str
     */
    public static void FullScreenCapture(String str){
        try {
            // 1. 创建Robot对象,用于操作屏幕
            Robot robot = new Robot();

            // 2. 获取屏幕尺寸(全屏大小)
            Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
            Rectangle screenRectangle = new Rectangle(screenSize);

            // 3. 执行全屏截图
            BufferedImage screenImage = robot.createScreenCapture(screenRectangle);

            // 4. 保存图片到本地(格式支持:png、jpg、gif)
            String path = new Utils().path(str);
            File outputFile = new File(path);
            if(!outputFile.getParentFile().isDirectory())outputFile.mkdirs();
            ImageIO.write(screenImage, "png", outputFile);
//
//            System.out.println("全屏截屏成功!图片保存路径:" + outputFile.getAbsolutePath());

        } catch (AWTException e) {
            System.err.println("截屏工具初始化失败:" + e.getMessage());
        } catch (IOException e) {
            System.err.println("图片保存失败:" + e.getMessage());
        }
    }


}

2.登录接口测试代码

java 复制代码
package chatroom.TestApi.Login;

import chatroom.TestApi.Utils.Utils;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.io.IOException;
import java.time.Duration;

public class Login extends Utils {
    private static final String url = "http://127.0.0.1:9091/login.html";
    public Login() {
        super(url);
    }

    public void verificationIsLogin(){
        // 进行校验
        webDriver.findElement(By.cssSelector("body > div.login-container > div > h3"));
        webDriver.findElement(By.cssSelector("#submit"));
        System.out.println("登录页面正常打开");
    }

    public void NormalLogin(String username,String password){
        webDriver.findElement(By.cssSelector("#username")).clear();
        webDriver.findElement(By.cssSelector("#password")).clear();
        webDriver.findElement(By.cssSelector("#username")).sendKeys(username);
        webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
        webDriver.findElement(By.cssSelector("#submit")).click();
        // 进行校验
        WebDriverWait wait = new WebDriverWait(webDriver, 3);
        wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(By.cssSelector("body > div.client-container > div > div.left > div.tab > div.tab-session")));
        wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(By.cssSelector("body > div.client-container > div > div.left > div.tab > div.tab-friend")));
    }
    /**
     * 账号为空
     */
    public void AccountIsNullLogin(String password) throws InterruptedException, IOException {
        webDriver.findElement(By.cssSelector("#username")).clear();
        webDriver.findElement(By.cssSelector("#password")).clear();
        webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
        webDriver.findElement(By.cssSelector("#submit")).click();
        Thread.sleep(500);
        WebElement popup = webDriver.findElement(By.cssSelector("body > div.jq-toast-wrap.bottom-left > div > h2"));
        assert popup.getText().equals("警告") : "用户名为空时提示错误";
        getScreenShot("用户名为null参数校验失败-"+getCurrentMothed());
        webDriver.findElement(By.cssSelector("body > div.jq-toast-wrap.bottom-left > div > span.close-jq-toast-single")).click();

    }
    /**
     * 账号错误
     */
    public void AccountIsFailLogin(String fakeUsername,String password) throws InterruptedException, IOException {
        Thread.sleep(200);
        webDriver.findElement(By.cssSelector("#username")).clear();
        webDriver.findElement(By.cssSelector("#username")).sendKeys(fakeUsername);
        webDriver.findElement(By.cssSelector("#password")).clear();
        webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
        webDriver.findElement(By.cssSelector("#submit")).click();
        Thread.sleep(500);
        WebElement popup = webDriver.findElement(By.cssSelector("body > div.jq-toast-wrap.bottom-left > div > h2"));
        assert popup.getText().equals("警告") : "用户名为空时提示错误";
        getScreenShot("用户名错误参数校验失败-"+getCurrentMothed());
        webDriver.findElement(By.cssSelector("body > div.jq-toast-wrap.bottom-left > div > span.close-jq-toast-single")).click();
    }
    /**
     * 密码为空
     */
    public  void PasswordIsNUllFailLogin(String username) throws InterruptedException, IOException {
        Thread.sleep(200);
        webDriver.findElement(By.cssSelector("#username")).clear();
        webDriver.findElement(By.cssSelector("#username")).sendKeys(username);
        webDriver.findElement(By.cssSelector("#password")).clear();
        webDriver.findElement(By.cssSelector("#submit")).click();
        Thread.sleep(500);
        WebElement popup = webDriver.findElement(By.cssSelector("body > div.jq-toast-wrap.bottom-left > div > h2"));
        assert popup.getText().equals("警告") : "用户名为空时提示错误";
        getScreenShot("密码为空校验失败-"+getCurrentMothed());
        webDriver.findElement(By.cssSelector("body > div.jq-toast-wrap.bottom-left > div > span.close-jq-toast-single")).click();
    }
    /**
     * 密码错误
     */
    public void PasswordIsFailLogin(String username,String fakePassword) throws InterruptedException, IOException {
        Thread.sleep(200);
        webDriver.findElement(By.cssSelector("#username")).clear();
        webDriver.findElement(By.cssSelector("#username")).sendKeys(username);
        webDriver.findElement(By.cssSelector("#password")).clear();
        webDriver.findElement(By.cssSelector("#password")).sendKeys(fakePassword);
        webDriver.findElement(By.cssSelector("#submit")).click();
        Thread.sleep(500);
        WebElement popup = webDriver.findElement(By.cssSelector("body > div.jq-toast-wrap.bottom-left > div > h2"));
        assert popup.getText().equals("警告") : "用户名为空时提示错误";
        getScreenShot("密码错误校验失败-"+getCurrentMothed());
        webDriver.findElement(By.cssSelector("body > div.jq-toast-wrap.bottom-left > div > span.close-jq-toast-single")).click();
    }
}

3.注册功能测试代码

java 复制代码
package chatroom.TestApi.Model;

public class RegisterModel {
    private String username;
    private String nickname;
    private String password;
    private String repeatedPassword;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getRepeatedPassword() {
        return repeatedPassword;
    }

    public void setRepeatedPassword(String repeatedPassword) {
        this.repeatedPassword = repeatedPassword;
    }
}

4.首页功能测试代码

java 复制代码
package chatroom.TestApi.HomePage;

import chatroom.Common.Common;
import chatroom.TestApi.Utils.Utils;
import org.openqa.selenium.By;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.time.Duration;

public class HomePage extends Utils {

    private static final String URL = "http://127.0.0.1:9091/login.html";
    private static final String LOGIN_URL = "http://127.0.0.1:9091/client.html";
    public HomePage() {
        super(LOGIN_URL);
    }

    /**
     * 直接进入首页,提示登录失败,并跳转到登录页面
     */
    public void notEnterClientPage(){
        System.out.println("当前的首页的url>:"+webDriver.getCurrentUrl());

        WebDriverWait wait = new WebDriverWait(webDriver, 5);
        wait.until(ExpectedConditions.urlContains("login.html"));

        String currentUrl = webDriver.getCurrentUrl();
        System.out.println("跳转后的url页面>:"+currentUrl);

        // 判断是不是sign-in.html
        assert currentUrl.equals(LOGIN_URL) : "未登录时的页面跳转失败,跳转的url是"+currentUrl;
        System.out.println("未登录时的页面跳转成功");
    }

    /**
     * 登录进去检查信息
     */
    public void sucEnterClientPage(){
        login("zhangsan","123456");

        WebDriverWait wait = new WebDriverWait(webDriver, 5);
        wait.until(ExpectedConditions.urlContains("client.html"));
        String currentUrl = webDriver.getCurrentUrl();
        assert currentUrl.equals(LOGIN_URL) : "未登录时的页面跳转失败,跳转的url是"+currentUrl;
        // 检查界面元素
        wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(By.cssSelector("body > div.client-container > div > div.left > div.tab > div.tab-session")));
        wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(By.cssSelector("body > div.client-container > div > div.left > div.tab > div.tab-friend")));
    }

    /**
     * 普通的web
     */
    public void userWebDriver(){
        Common.SessionNorDisplay(webDriver);
        Common.FriendListNorDisplay(webDriver);
        Common.ApplyNorDisplay(webDriver);
    }

    /**
     * 无痕浏览器
     */
    public void userTraceDriver() throws InterruptedException {
        // 先登录
        TraceLogin("testName","123456",URL,false);
        Thread.sleep(500);
        Common.SessionNorDisplay(traceless);
        Common.FriendListNorDisplay(traceless);
        Common.ApplyNorDisplay(traceless);
    }



}

5.添加好友功能测试代码

java 复制代码
package chatroom.TestApi.FriendApply;

import chatroom.Common.Common;
import chatroom.TestApi.Send.SendMessage;
import chatroom.TestApi.Utils.Utils;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import javax.swing.text.TabExpander;

import java.io.IOException;
import java.time.Duration;

import static chatroom.Main.sendMessage;

public class FriendApply extends Utils {
    private static final String URL = "http://127.0.0.1:9091/login.html";
    public FriendApply() {
        super(URL);
    }


    public void applyFriend() throws InterruptedException, IOException {
        // 先打开两个浏览器
        // 接着左右分屏
        login("zhangsan","123456");
        setLeftWindow(webDriver);
        TraceLogin("testName","123456",URL,true);

        // 1.开始时需要截图双方的会话  好友   好友申请
        getAllScreenShot();

        // 2.张三发送好友申请,testName 拒绝,此时先截图,再点击拒绝
        String searchContent = "testName";
        String applyContent = "你好,testName想认识一下你~~";
        sendApply(searchContent,applyContent);
        rejectedApply();
        Thread.sleep(2000);

        // 3.张三重新发送好友申请,testName 接受,此时 进行一次消息发送
        sendApply(searchContent,applyContent);
        Thread.sleep(1000);
        AgreeApply();
    }

    /**
     * 同意申请
     */
    private void AgreeApply() throws InterruptedException {
        traceless.navigate().refresh();
        Thread.sleep(2000);
        traceless.findElement(By.xpath("/html/body/div[2]/div/div[1]/div[3]/div[3]")).click();
        Thread.sleep(100);
        traceless.findElement(By.cssSelector("#button_right > button.agree")).click();
        // 获取弹窗
        String text = traceless.findElement(By.cssSelector("body > div.jq-toast-wrap.bottom-left > div > h2")).getText();
        assert text.equals("成功") : "点击添加好友,显示错误";
        Thread.sleep(250);
        Common.FullScreenCapture("添加好友后的会话列表");

        // 聊天
        SendMessage.reallySendMessage(webDriver,traceless,true,4);

        // 点击好友列表查看
        webDriver.findElement(By.cssSelector("body > div.client-container > div > div.left > div.tab > div.tab-friend")).click();
        traceless.findElement(By.cssSelector("body > div.client-container > div > div.left > div.tab > div.tab-friend")).click();
        Common.FullScreenCapture("添加好友后的好友列表");
    }

    /**
     * 拒绝申请
     */
    private void rejectedApply() throws InterruptedException {
        traceless.navigate().refresh();
        Thread.sleep(2000);
        traceless.findElement(By.xpath("/html/body/div[2]/div/div[1]/div[3]/div[3]")).click();
        Thread.sleep(100);
        traceless.findElement(By.cssSelector("#button_right > button.reject")).click();
        WebElement popup = traceless.findElement(By.cssSelector("body > div.jq-toast-wrap.bottom-left > div"));
        String text = popup.findElement(By.cssSelector("div > h2")).getText();
        assert text.equals("成功") : "点击好友申请拒绝按钮后,内容显示错误";
        // 截图
        Common.FullScreenCapture("好友申请拒绝后截图");
        WebDriverWait wait = new WebDriverWait(traceless, 15);
        wait.until(ExpectedConditions.invisibilityOf(popup));
    }

    /**
     * 搜索对应的好友并发送请求
     * @param searchContent  搜索框内容
     * @param applyContent   申请理由
     */
    private void sendApply(String searchContent,String applyContent) throws InterruptedException {
        WebElement search = webDriver.findElement(By.cssSelector("body > div.client-container > div > div.left > div.search > input[type=text]"));
        search.sendKeys(searchContent);
        webDriver.findElement(By.cssSelector("body > div.client-container > div > div.left > div.search > button")).click();
        // 检查元素是否清空
        String text = search.getText();
        assert text.length() == 0 && text.equals("") : "输入框没有清空";
        // 输入申请理由
        WebElement element = webDriver.findElement(By.cssSelector("body > div.client-container > div > div.right-friend-search > div.friend-list > div"));
        element.findElement(By.cssSelector("div.name-and-input > input")).sendKeys(applyContent);
        // 点击发送
        Thread.sleep(1000);
        webDriver.findElement(By.cssSelector("div.apply > button")).click();
        // 判断接受状态
        assert webDriver.findElement(By.cssSelector("div.apply > button")).getText().equals("已发送") : "发送按钮点击后,状态显示异常";
        traceless.findElement(By.cssSelector("body > div.client-container > div > div.left > div.tab > div.tab-request")).click();
        Thread.sleep(1000);
        // 截图
        Common.FullScreenCapture("发送好友请求截图");
    }

    private  void getAllScreenShot() throws InterruptedException {
        // 1.选中session.截图
        webDriver.findElement(By.cssSelector("body > div.client-container > div > div.left > div.tab > div.tab-session")).click();
        traceless.findElement(By.cssSelector("body > div.client-container > div > div.left > div.tab > div.tab-session")).click();
        Common.FullScreenCapture("初始会话列表截图");
        // 2.选中 好友列表,截图
        Thread.sleep(250);
        webDriver.findElement(By.cssSelector("body > div.client-container > div > div.left > div.tab > div.tab-friend")).click();
        traceless.findElement(By.cssSelector("body > div.client-container > div > div.left > div.tab > div.tab-friend")).click();
        Common.FullScreenCapture("初始好友列表列表截图");
        // 3.选中好友申请,截图
        Thread.sleep(250);
        webDriver.findElement(By.cssSelector("body > div.client-container > div > div.left > div.tab > div.tab-request")).click();
        traceless.findElement(By.cssSelector("body > div.client-container > div > div.left > div.tab > div.tab-request")).click();
        Common.FullScreenCapture("初始好友申请列表截图");

    }

}

6.发送消息功能测试代码

java 复制代码
package chatroom.TestApi.Send;

import chatroom.Common.Common;
import chatroom.TestApi.Utils.Utils;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.io.IOException;
import java.time.Duration;
import java.util.List;

public class SendMessage extends Utils {
    private static final String URL = "http://127.0.0.1:9091/login.html";
    public SendMessage() {
        super(URL);
    }

    /**
     * 发送消息
     * @param flag (true 表示点击会话区域发送消息   false表示点击好友列表发送消息)
     * @param row  发送几条消息
     * @throws InterruptedException
     * @throws IOException
     */
    public void Message(boolean flag,int row) throws InterruptedException, IOException {
        // 先打开两个浏览器
        // 接着左右分屏
        login("zhangsan","123456");
        setLeftWindow(webDriver);
        TraceLogin("testName","123456",URL,true);
        // 双方进行发送消息验证
        reallySendMessage(webDriver,traceless,true,row);
    }

    /**
     * 发送消息(正式版,在 FriendApply 用到,此处将代码提取进行封装)
     */
    public static void reallySendMessage(WebDriver webDriver,WebDriver traceless,boolean flag,int row) throws InterruptedException {
        choiceSession(webDriver,true);// 这里先不用 flag,待后续逻辑补充
        choiceSession(traceless,true);
        // 一个一个给对方发消息
        // 在这里,先获取当前的会话的数据,方便后续进行选中元素并校验
        List<WebElement> elements = webDriver.findElements(By.cssSelector("body > div.client-container > div > div.right > div.message-show > div"));
        //    消息       数组下标    dom元素下标
        int message = 0,index = 0,eleCount = elements.size();
        WebDriver[] list = new WebDriver[]{webDriver,traceless};
        String send = null;
        for(int i = 0;i < row;i++){
            Thread.sleep(500);
            send = send(list[index++], message++);
            eleCount++;// 发送消息数目加一
            // 对方查看消息框,检验消息是否正确
            if(index >= 2)index %= list.length;// 更新数组下标
            String text = list[index].findElement(By.xpath("/html/body/div[2]/div/div[2]/div[2]/div[" + eleCount + "]/div/p")).getText();
            assert text.equals(send) : "发送的消息与接受的消息不一样";
            // 接收方接受的消息没问题,那就开始发送
        }
        Common.FullScreenCapture("发消息校验"+Utils.getStaticCurrentMothed());
    }

    /**
     * 选中对话
     * @param driver
     */
    private static void choiceSession(WebDriver driver,boolean flag) throws InterruptedException {

        // 点击会话标签
        WebElement webElement = slidePage("body > div.client-container > div > div.left > div.tab > div.tab-session");
        webElement.click();



        if(flag) driver.findElement(By.xpath("//*[@id=\"session-list\"]/li[1]")).click();
        // else 扩展点击好友列表的好友,进入聊天的功能测试
    }

    private static String send(WebDriver driver,int message){
        // 寻找输入框
        // 输入元素
        // 发送
        String var = String.valueOf(message);
        String ele = var + var + var;
        driver.findElement(By.cssSelector("body > div.client-container > div > div.right > textarea")).sendKeys(ele);
        driver.findElement(By.cssSelector("body > div.client-container > div > div.right > div.ctrl > button")).click();
        return ele;


    }


}

四.接口测试

1.登录接口

2.注册接口

3.首页接口

4.发送好友请求接口

5.发送消息接口

五.界面测试

(1).登录界面:

图片正确显示、不遮挡关键信息、页面无错别字:

信息提示正确,无遮挡

(2). 注册界面

图片正确显示、不遮挡关键信息、页面无错别字:

错误提示正确,无遮挡>:

(3).首页界面

首页元素无遮挡、显示排版正确,文字图标描述清晰>:

(4).添加好友界面

界面无遮挡、格式排版符合正常使用,文字正确,描述清晰>:

提示清晰准确,无遮挡>:

点击拒绝按钮>:

点击同意按钮,并创建会话>:

(5).发送消息

界面显示正确,信息排版正确,无遮挡、无错误>:

六.兼容性测试

①在Edge浏览器下进入网络聊天室

预期结果:无异常且一切布局显示功能等与其一致

②在Chrome浏览器下进入网络聊天室

预期结果:无异常且一切布局显示功能等与其一致

七.安全测试

场景一:未登录状况下,是否能访问除登陆注册外其他功能或板块

结果:无法访问除登陆注册外的其它板块

场景二:Fidder抓包

预期结果:对于敏感信息密文传输,无法获取具体的信息

结果:账号密码显示明文,协议应该升级为https

八.性能测试

1.聚合报告

a. 整体表现

  • 总样本数:27230 次
  • 平均响应时间:12 ms
  • 异常率:1.93%(整体可控)
  • 吞吐量:340.4/sec(系统处理能力较强)

b. 核心指标拆解

c. 重点问题接口

  1. 添加好友

    • 平均响应 73ms,最大值 207ms,标准差 11.51(波动大)
    • 异常率 14.10%,是故障重灾区
    • 可能原因:数据库事务锁、好友关系校验逻辑复杂、网络 IO 阻塞
  2. 拒绝好友申请 / 登录其他用户

    • 异常率 14.10%,和「添加好友」同步异常
    • 推测是业务流程依赖:拒绝 / 添加操作依赖同一套用户状态校验,导致连锁失败
  3. 根据元素模糊查找用户

    • 平均 50ms,最大值 173ms,标准差 7.85
    • 可能原因:未建索引、模糊查询 LIKE 效率低、数据量过大

d.优化建议

  • **优化索引:「用户表(friend)」「好友关系表(session_message_user)」**添加合理索引,优化模糊查询和关联查询
  • 结果异步化处理: 重构「添加好友」等逻辑,减少锁竞争,将非核心操作异步化
  • **缓存优化:**采用redis,优化查询速度

2.tps报告

a. 图表元素

  • 横轴:时间(Elapsed time),粒度为 1 秒,覆盖测试全程(约 1 分 20 秒)。
  • 纵轴:每秒事务数(Number of transactions/sec),反映接口每秒能处理的成功请求数。
  • 多色折线:每条折线对应一个系统接口,图例标注了接口类型(如 "登录""添加好友""获取好友列表" 等),且均为 "success",代表成功事务的吞吐量。

b 阶段分析

  1. 流量爬坡阶段(0s ~ 15s)

    • 表现:核心接口(如登录)TPS 从 0 快速飙升至~55 TPS 的峰值,其他接口同步爬坡。
    • 原因:阶梯线程组逐步启动线程,系统瞬间接入大量流量,处于预热 + 负载适应状态。
    • 波动:登录接口曲线剧烈抖动,说明高并发下系统资源(CPU、数据库、IO)开始出现竞争,处理能力尚未稳定。
  2. 稳定负载阶段(15s ~ 72s)

    • 表现:登录接口 TPS 稳定在 40~55 区间,其他核心业务接口(如获取好友列表、发送消息)TPS 稳定在 12~40 区间,波动幅度逐渐收窄
    • 描述:系统在持续压力下的真实处理能力,代表长期可支撑的业务吞吐量
    • 详细
      • 登录接口流量占比最高,是当前压测的核心流量入口
      • 其他业务接口流量分布均匀,核心流程整体稳定
      • 失败类事务(如添加好友失败、拒绝好友申请失败)TPS 极低,说明业务成功率较高
  3. 流量衰减阶段(72s 之后)

    • 表现:所有接口 TPS 逐步下降,最终趋近于 0。
    • 原因:阶梯线程组开始按配置逐步停止线程,负载自然下降,曲线平滑回落

c. 吞吐量趋势

(1).总结

(2). 原因分析

  • 读操作(如获取好友列表、查询历史记录):TPS 相对较高,能支撑 30~40 的稳定吞吐量
  • 写操作(如添加好友、发送消息):TPS 较低,稳定在 12~20 区间,存在锁竞争或数据库写入瓶颈
  • 登录接口:负载最高,是当前系统的主要压力来源

(3). 优化方向

1> 加索引:对用户表、好友关系表添加合理索引,优化模糊查询和关联查询,避免全表扫描

2> Redis 缓存:将用户信息、好友列表、会话消息等高频读请求缓存到 Redis,减轻数据库读压力,提升查询速度

3> 异步化:重构 "添加好友" 等写操作逻辑,减少锁竞争,将非核心操作(如通知、统计)放入消息队列异步处理

3.响应时间可视化

a. 图表结构与元素

  • 横轴:时间(从 00:00:00 到 00:01:20 左右),反映测试的时间进程。
  • 纵轴:响应时间(单位 ms),体现接口处理请求的耗时。
  • 多色折线:每条折线对应一个系统接口,图例标注了接口类型,如 "登录""添加好友""获取好友列表""发送消息" 等。

b. 性能趋势分析

1. 整体性能表现

  • 响应时间分布 :大部分接口响应时间集中在 10--80ms,整体表现稳定。
  • 波动趋势 :随着压测时间推进,首页发送消息等核心接口响应时间逐步上升,存在一定的性能衰减。
  • 峰值情况 :最高响应时间出现在 添加好友 接口,峰值约 175ms

2. 接口性能分析

c. 关键问题与风险点

1. 核心接口性能衰减

  • 添加好友发送消息首页 等接口,响应时间从初始的 30--50ms 逐步攀升至 70--95ms,说明系统在持续压测下存在资源耗尽或处理延迟。

2. 瞬时尖峰问题

  • 多个接口出现瞬时尖峰(如添加好友 峰值 175ms),可能由以下原因导致:
    1. 数据库慢查询(如多表关联、未加索引)
    2. 垃圾回收(GC)停顿
    3. 线程阻塞或锁竞争(如添加好友时的事务锁)
    4. 数据库连接池耗尽
  1. 热点接口集中
  • 高耗时接口多集中在用户交互类写操作(添加好友、发送消息),这类操作涉及数据写入与事务,是性能优化的核心目标。

d. 优化方向

  1. 加索引:对用户表、好友关系表添加合理索引,优化模糊查询和关联查询,避免全表扫描。
  2. Redis 缓存:将用户信息、好友列表、首页数据等高频读请求缓存到 Redis,减轻数据库读压力。
  3. 异步化:重构 "添加好友""发送消息" 等写操作逻辑,减少锁竞争,将非核心操作(如通知、统计)放入消息队列异步处理。
  4. 连接池优化:调整数据库连接池大小,避免连接耗尽导致的响应延迟。

4.测试报告

错误描述>:

**(1).**本次性能测试中:

总错误数: 48

总样本数: 19855

说明:大部分请求是成功的,只有约 0.24% 的请求因断言不通过标记为失败,且主要集中在返回 6003 的场景(删除失败,该聊记录不存在或已被删除)

**(2).**可能原因>:

a.网络波动

• 测试环境或生产环境的网络链路不稳定(如丢包、延迟突然升高、带宽拥堵),导致请求 / 响应数据传输耗时增加。

• 客户端与服务器之间的网络路由跳转过多,也可能引发响应时间波动。

b.并发请求处理能力不足

同一时间发起大量请求(如批量获取数据、高并发场景),服务器资源(CPU、内存、线程池)被占满,无法及时处理新请求,导致排队等待时间过长,以及数据被处理了,但没有同步更新

c.数据状态变化:

比如删除了好友请求,本应该消失的数据却依然显示,导致后续点击出现6003错误

九.总结

一、测试范围与内容
1.功能测试

• 注册、登录、好友管理、添加 / 拒绝 / 同意好友、发送消息、会话列表、首页展示

• 空值、错误参数、未授权访问等异常场景校验
2.自动化测试

基于 Selenium 实现 WebUI 自动化,覆盖登录、注册、首页、好友、发消息等核心流程

包含公共方法、断言、截图、多浏览器并行验证
3.接口测试(JMeter)

登录 / 注册 / 首页 / 模糊搜索 / 好友申请 / 发消息 / WebSocket 等全接口

断言、参数化、循环、结果树校验
4.界面测试

布局、文字、提示、图标、交互无遮挡、无错乱、提示准确
5.兼容性测试

Chrome、Edge 浏览器:功能与显示完全一致
6.安全测试

未登录拦截正常;账号密码明文传输,未用 HTTPS
7.性能测试(JMeter)

聚合报告、TPS、响应时间、APDEX、错误统计
二、核心测试结果
1. 功能与界面

• 所有业务流程正常可用

• 输入校验、弹窗提示、页面跳转符合预期

• 界面排版正常、无遮挡、无错别字
2. 兼容性

Chrome、Edge完全兼容,无差异
3. 安全性(主要问题)

✅ 未登录无法访问业务页面,拦截有效

❌ 登录密码明文传输,未使用 HTTPS,存在泄露风险
4. 性能(关键结论)

(1).总样本:19855,失败 48,错误率 0.24%

(2).APDEX 0.995,整体体验优秀

(3).吞吐量:248.55/sec,处理能力较强

(4).平均响应:3.73ms,多数接口极快

(5).性能瓶颈接口

• 添加好友:平均 19.39ms,最大 52ms

• 拒绝好友 / 登录其他用户:错误率 3.61%

• 模糊搜索用户:响应偏慢,无索引导致

• 错误原因:返回 6003(数据状态不同步、记录不存在)
三、主要问题汇总

• 安全:密码明文、未使用 HTTPS

• 性能:添加好友、模糊查询慢;好友相关操作偶发失败

• 稳定性:高并发下数据状态不同步,导致 6003 错误

• 数据库:缺少索引,写操作锁竞争明显
四、优化建议

• 安全:升级 HTTPS,密码加密传输

• 数据库:用户表、好友表加索引,优化模糊查询

• 性能:Redis 缓存好友 / 会话列表;添加好友异步化

• 稳定性:修复数据状态同步问题,优化并发事务
五、整体总结

本次针对网络聊天室项目开展了功能、界面、兼容性、安全、接口自动化及性能等多方面全面测试。结果表明:项目核心业务流程完整可用,界面展示正常,多浏览器兼容性良好,接口响应速度快,整体用户体验优秀。

但项目仍存在明显不足:密码明文传输存在安全隐患;高并发场景下部分接口出现请求失败,错误率偏高;模糊查询、好友相关操作响应较慢,受数据库索引缺失、锁竞争及并发数据不同步影响。

整体而言,系统基础功能已满足使用要求 ,性能与稳定性基本达标,但在安全防护、高并发稳定性、数据库效率上存在短板,经针对性优化完善后,可满足更稳定、安全的上线运行条件。

相关推荐
2301_805962932 小时前
ESP32 HTTP OTA 本地测试教程
网络·网络协议·http
小陈工2 小时前
ModelEngine智能体开发实战:知识库自动生成与多Agent协作
大数据·网络·数据库·人工智能·python·django·异步
奥地利落榜美术生灬2 小时前
图床项目总结
网络
Rabbit_QL2 小时前
【HTTP协议解读】01小白篇:理解互联网的通信语言HTTP
网络·网络协议·http
liulilittle2 小时前
LINUX RING BUFFER TUN/TAP 2
linux·运维·服务器·开发语言·网络·c++
@insist1234 小时前
软件设计师-网络层核心知识全解:广域网协议、TCP/IP 体系与 IP 地址规划
网络·网络协议·tcp/ip·软考·软件设计师·软件水平考试
旺仔.29111 小时前
Linux 信号详解
linux·运维·网络
源远流长jerry14 小时前
在 Ubuntu 22.04 上配置 Soft-RoCE 并运行 RDMA 测试程序
linux·服务器·网络·tcp/ip·ubuntu·架构·ip
虾..15 小时前
UDP协议
网络·网络协议·udp