AI 聊天助手 — 自动化测试与性能测试综合报告

测试日期:2026-05-09 ~ 2026-05-10
测试目标http://<server-address>:8080/
测试环境:Python 3.12 + Selenium 4.43 + Chrome 147 + JMeter 5.6.3 + Java 21
测试类型:UI 自动化测试(Page Object Model)+ API 性能测试
后端技术栈:C++ httplib + SQLite


一、项目背景

AI 聊天助手是一个基于 Web 的多模型 AI 对话平台,旨在为用户提供便捷的智能对话服务。系统集成了多种主流大语言模型(DeepSeek、DeepSeek-R1、Gemini、GPT-4o-Mini),支持用户自由切换模型、管理历史会话、查看 Markdown/代码块一键复制渲染等内容。本项目通过 Selenium UI 自动化测试,对系统各核心页面进行功能验证,确保界面元素、交互逻辑和业务流程的正确性与稳定性。


二、项目简介

本系统包含以下核心功能模块:

  1. 默认界面(DefaultInterface):系统首页,包含左侧导航栏(AI 图标、"AI聊天助手"标题、新建对话按钮)和右侧欢迎页(引导文案、新建对话入口)。

  2. 模型选择(ModelSelection):新建对话时弹出模型选择窗口,展示 4 个可选模型(deepseek-chat、deepseek-r1:1.5b、gemini-3.1-flash-lite-preview、gpt-4o-mini),支持确认创建或取消操作。

  3. 历史会话列表(HistorySessionList):左侧会话列表,按时间降序排列,展示会话时间、消息预览、模型标签,支持会话切换、悬停删除、滚动浏览等功能。

  4. 聊天消息显示(ChatMessageDisplay):聊天区域核心模块,包含模型名称展示、消息气泡(AI/用户)、思考过程面板(r1 模型)、Markdown 表格渲染、代码块语法高亮与复制等功能。

  5. 用户输入编辑器(UserInputEditor):底部输入区域,支持 placeholder 提示、多行输入与滚动、字数实时统计(上限 2000 字)、发送按钮状态控制等功能。


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三、测试计划

测试策略

各页面模块独立进行功能测试,最后通过 Main.py 整合回归测试,确保模块间无兼容性问题。

提测方式:分模块提测 — 各模块功能相对独立,耦合度低(共享同一个 WebDriver 实例和页面会话),适合分模块开发和测试。

测试范围

模块 测试方法数 测试覆盖内容
DefaultInterface 3 左侧导航栏元素、右侧欢迎页元素、新建对话按钮点击
ModelSelection 7 弹窗元素完整性、4 个模型选择、创建成功/取消场景
HistorySessionList 10 列表结构、排序、悬停不切换、删除/取消删除、滚动条、预览文本、时间更新
ChatMessageDisplay 8 模型名称、滚动条、AI 消息区、思考过程展开/折叠、Markdown 表格、代码块渲染/复制、用户消息区
UserInputEditor 10 placeholder、发送按钮状态、编辑器高度/滚动、字数统计实时更新、字数上限
合计 38 全部 PASS

设计测试用例

测试执行顺序

DefaultInterface → ModelSelection → HistorySessionList → ChatMessageDisplay → UserInputEditor → 回归测试 (Main.py)

四、测试工具

工具 / 框架 用途 版本
Python 测试脚本开发语言 3.12
Selenium WebDriver UI 自动化测试核心框架 4.43
Google Chrome 测试浏览器 147
webdriver_manager ChromeDriver 自动管理 最新
Utils.py (AIChatDriver) 自定义工具类:单例 WebDriver 管理 + 自动截图
Visual Studio Code 测试开发与调试 IDE
JMeter 5.6.3 API 性能 / 负载 / 混合场景测试 已完成
ConcurrencyThreadGroup JMeter 阶梯加压插件 3.1.1
Plugins Manager JMeter 插件管理 1.12

未覆盖的工具(后续可补充)

工具 用途 状态
Postman 接口功能测试 开发阶段已实施(后端 API 文档已具备)
Pytest 接口自动化 / 测试框架升级 未实施

五、测试类型与覆盖情况

测试类型概览

测试类型 覆盖范围 发现/修复问题数 备注
UI 功能测试 5 个模块全部核心功能(38 个测试方法) 约 10 覆盖元素存在性、交互逻辑、样式验证、边界场景
回归测试 Main.py 整合各模块串联流程 手动取消注释执行各模块
API 性能测试 7 个 REST API、4 个场景 2 个服务端 P0 Bug 基准/负载/混合场景,并发上限 5 用户
接口测试 未覆盖 后端 API 文档已具备,可后续补充 Pytest

模块覆盖详情

功能模块 测试方法 通过率 覆盖场景
DefaultInterface(默认界面) 3 3/3 左侧导航元素、右侧欢迎页、新建对话按钮
ModelSelection(模型选择) 7 7/7 弹窗结构、4 模型选择、创建成功/取消
HistorySessionList(历史会话) 10 10/10 列表结构、排序、悬停、删除、滚动、预览、时间更新
ChatMessageDisplay(消息显示) 8 8/8 模型名、滚动条、消息区域、思考过程、Markdown/代码渲染、用户消息
UserInputEditor(输入编辑器) 10 10/10 placeholder、按钮状态、编辑器高度/滚动、字数统计
合计 38 38/38 全模块全方法 100% 通过

六、功能测试

6.1 DefaultInterface — 默认界面

测试场景: 打开系统首页,验证未登录/无会话状态下的默认界面元素完整性。

用例 ID 用例名称 测试步骤 预期结果 执行结果
DF-001 CheckDefaultLeftTop 1. 打开首页;2. 定位左侧 header 区域 AI logo SVG 元素存在;标题文本为"AI聊天助手";#new-chat-btn 按钮可见 PASS
DF-002 CheckDefaultRight 1. 打开首页;2. 定位右侧欢迎区域 欢迎页 AI logo SVG 存在;引导文案正确;#welcome-new-chat 按钮可见 PASS
DF-003 ClickNewSession 1. 打开首页;2. 点击 #new-chat-btn 按钮可点击,触发模型选择弹窗弹出 PASS

关键代码:

class DefaultAIChat:
    def CheckDefaultLeftTop(self):
        """Verify left sidebar: logo SVG, title text, and new-chat button."""
        self.driver.find_element(By.CSS_SELECTOR, "...")
        text = self.driver.find_element(By.CSS_SELECTOR, "... > span").text
        assert text == "AI聊天助手"
        self.driver.find_element(By.CSS_SELECTOR, "#new-chat-btn")
        AIChatDriver.getScreenShot()

    def ClickNewSession(self):
        """Click the new-chat button to open model selection modal."""
        button = WebDriverWait(self.driver, 5).until(
            EC.element_to_be_clickable((By.CSS_SELECTOR, "#new-chat-btn")))
        button.click()
        AIChatDriver.getScreenShot()

6.2 ModelSelection — 模型选择

测试场景: 点击"新建对话"后弹窗展示 4 个模型,验证模型选择、确认创建和取消创建流程。

用例 ID 用例名称 测试步骤 预期结果 执行结果
MS-001 elementExists 1. 打开模型弹窗;2. 逐一检查元素 4 个模型名称(deepseek-chat / deepseek-r1:1.5b / gemini-3.1-flash-lite-preview / gpt-4o-mini)及描述正确显示;取消/确认按钮可见 PASS
MS-002 chooseDeepSeek 1. 打开弹窗;2. 点击选择 deepseek-chat 模型可点击选择,截图验证 PASS
MS-003 chooseDeepSeekR1 1. 打开弹窗;2. 点击选择 deepseek-r1:1.5b 模型可点击选择,截图验证 PASS
MS-004 chooseGemini 1. 打开弹窗;2. 点击选择 gemini-3.1-flash-lite-preview 模型可点击选择,截图验证 PASS
MS-005 chooseGPT 1. 打开弹窗;2. 点击选择 gpt-4o-mini 模型可点击选择,截图验证 PASS
MS-006 newSessionSucTest 1. 选择模型;2. 点击"确认"按钮 弹窗关闭,新会话创建,会话时间与当前时间差 < 5 秒 PASS
MS-007 newSessionFailTest 1. 打开弹窗;2. 不选模型直接点击"取消" 弹窗关闭,未创建新会话,原有会话时间与当前时间差 > 2 秒 PASS

关键代码:

class ModelSelection:
    def elementExists(self):
        """Check model selection modal element existence."""
        items = self.driver.find_elements(*self.MODAL_ITEMS)
        assert len(items) == 4
        assert self.driver.find_element(*self.CONFIRM_BTN).is_displayed()
        assert self.driver.find_element(*self.CANCEL_BTN).is_displayed()
        AIChatDriver.getScreenShot()

    def newSessionSucTest(self):
        """Test successful session creation via confirm button."""
        old_time = datetime.datetime.now()
        self.driver.find_element(*self.CONFIRM_BTN).click()
        time.sleep(1)
        # ...verify session time difference < 5 seconds

6.3 HistorySessionList — 历史会话列表

测试场景: 验证左侧会话列表的结构完整性、排序规则、交互行为(悬停/点击/删除)和滚动功能。

用例 ID 用例名称 测试步骤 预期结果 执行结果
HS-001 check_element_existence 1. 加载页面;2. 获取会话列表 标题为"历史对话";每个会话项含时间/消息/模型标签;截图验证 PASS
HS-002 delete_first_session 1. 悬停会话项;2. 点击删除按钮;3. 确认 alert Alert 文案正确;确认后列表数量 -1 PASS
HS-003 cancel_delete_last_session 1. 悬停会话项;2. 点击删除按钮;3. 取消 alert 取消后列表数量不变 PASS
HS-004 verify_session_click_and_style 1. 点击某会话项 点击后出现 active 背景色;右侧聊天窗口加载对应消息 PASS
HS-005 verify_sessions_order 1. 提取所有会话时间;2. 转为 datetime;3. 比较相邻项 所有时间降序排列(最新会话在最前) PASS
HS-006 verify_hover_does_not_switch_chat 1. 记录当前消息 ID 指纹;2. 悬停某会话项;3. 再次比对消息 ID 悬停前后消息 ID 指纹一致,未触发会话切换 PASS
HS-007 verify_new_session_displays_new_chat 1. 创建新会话(无消息);2. 检查列表第 0 项预览 预览文本为"新对话" PASS
HS-008 verify_session_time_updates_after_message 1. 点击会话;2. 发送消息;3. 刷新页面 会话时间更新为新时间,且会话项移至列表顶部(index 0) PASS
HS-009 verify_session_preview_with_content 1. 发送短文本"你好";2. 刷新后检查预览;3. 发送长文本;4. 检查 CSS 溢出处理 短文本完整显示;长文本 text-overflow: ellipsis + white-space: nowrap + 宽度不超出父容器 PASS
HS-010 verify_session_list_scroll 1. 获取 scrollHeight / clientHeight;2. 判断是否有滚动条;3. 滚到底部→滚回顶部 scrollHeight > clientHeight 时出现滚动条;可滚到底部(最后项可见)和顶部(第一项可见) PASS

关键代码:

class HistorySessionList:
    TITLE_CSS = "aside .sidebar-header h3"
    SESSION_ITEMS = (By.CSS_SELECTOR, "#session-list .session-item")
    TIME_TAG = (By.CLASS_NAME, "session-time")
    MSG_TAG = (By.CLASS_NAME, "session-message")
    MODEL_TAG = (By.CLASS_NAME, "session-model")
    DELETE_BTN = (By.CLASS_NAME, "delete-btn")
    SESSION_LIST_CONTAINER = (By.CSS_SELECTOR, "#session-list")

    def verify_session_preview_with_content(self):
        """Verify short text complete display & long text overflow ellipsis."""
        # Short text: "你好"
        assert actual_preview == "你好"
        # Long text: CSS overflow check
        assert overflow_style == "ellipsis"
        assert white_space == "nowrap"
        assert element_width <= parent_width

    def verify_session_list_scroll(self):
        """Verify scrollbar appears & scroll to bottom/top works."""
        scroll_height = self.driver.execute_script(
            "return arguments[0].scrollHeight;", container)
        client_height = self.driver.execute_script(
            "return arguments[0].clientHeight;", container)
        has_scrollbar = scroll_height > client_height
        if has_scrollbar:
            # Scroll to bottom → verify last item visible
            # Scroll to top → verify first item visible

6.4 ChatMessageDisplay — 聊天消息显示

测试场景: 创建会话并发送消息后,验证聊天区域的模型名称、消息气泡、思考过程、Markdown 渲染、代码块渲染和用户消息区域。

用例 ID 用例名称 测试步骤 预期结果 执行结果
CM-001 check_model_name_display 1. 创建 DeepSeek 会话;2. 检查顶部模型名称 元素存在且文本为"deepseek-chat" PASS
CM-002 verify_chat_scrollbar 1. 发送代码类长消息;2. 等待回复;3. 检查 scrollHeight vs clientHeight scrollHeight > clientHeight;滚动条存在;可滚到底部 PASS
CM-003 check_model_message_area 1. 发送消息;2. 等待 AI 回复;3. 检查消息区域结构 模型头像(.message-avatar img)显示;消息容器(.message.ai)存在;消息正文非空;时间格式 YYYY/M/D HH:MM:SS 正确 PASS
CM-004 check_thinking_process_default_expand 1. 使用 r1 模型创建会话;2. 发送需推理的消息;3. 检查思考面板 .thinking-details 的 open 属性为 “true”(默认展开);思考内容非空 PASS
CM-005 check_thinking_process_toggle 1. 默认展开→点击折叠→再次点击展开 状态 1: open;状态 2: 无 open(折叠);状态 3: open 恢复(含容错:无思考内容时跳过) PASS
CM-006 check_markdown_rendering 1. 发送"生成表格"消息;2. 等待回复;3. 检查 .message-text table thead 存在(1 个);th 数量正确(4 列);tr 行数 > 0 PASS
CM-007 check_code_block_rendering 1. 发送"写代码"消息;2. 等待回复;3. 检查 pre code 元素 代码块存在(内容 > 0);有 language-xxx 语法高亮类名;复制按钮可见且可点击 PASS
CM-008 check_user_message_area 1. 发送唯一标识消息;2. 检查用户消息区域 用户头像显示;消息内容匹配;时间格式正确;时间差 < 10 秒(合理) PASS

关键代码:

class ChatMessageDisplay:
    def check_model_name_display(self, expected=None):
        """Verify model name element exists and text is correct."""
        el = WebDriverWait(self.driver, 10).until(
            EC.presence_of_element_located(self.MODEL_NAME_HEADER))
        actual = el.text.strip()
        assert actual == (expected or "deepseek-chat")

    def check_thinking_process_toggle(self):
        """Verify think panel expand/collapse/re-expand."""
        # State 1: default expanded
        assert details.get_attribute("open") == "true"
        # State 2: collapsed
        summary.click(); time.sleep(0.5)
        assert details.get_attribute("open") is None
        # State 3: re-expanded
        summary.click(); time.sleep(0.5)
        assert details.get_attribute("open") == "true"

    def check_code_block_rendering(self):
        """Verify code block rendering, highlight & copy button."""
        code_block = WebDriverWait(...).until(
            EC.presence_of_element_located(self.CODE_BLOCK))
        assert len(code_block.text) > 0
        # Syntax highlight class check
        class_attr = code_block.get_attribute("class")
        assert "language-" in class_attr or "hljs" in class_attr
        # Copy button
        copy_btn = self.driver.find_element(*self.COPY_BUTTON)
        assert copy_btn.is_displayed()

6.5 UserInputEditor — 用户输入编辑器

测试场景: 验证底部输入框的 placeholder、发送按钮状态联动、编辑器尺寸稳定性、滚动条行为和字数统计功能。

用例 ID 用例名称 测试步骤 预期结果 执行结果
UE-001 check_placeholder_display 1. 创建会话;2. 检查 #message-input 的 placeholder 属性 包含"Enter"和"换行"关键词(完整:请输入您的消息…Enter发送,Shift+Enter换行) PASS
UE-002 check_placeholder_disappear_after_input 1. 输入文本;2. 检查 value 属性 value 属性正确反映输入内容(placeholder 为静态属性,输入后不消失但视觉上隐藏) PASS
UE-003 check_send_button_disabled_when_empty 1. 空输入;2. 点击发送按钮 无用户消息创建(应用通过逻辑层阻止空消息发送,按钮无 DOM 级 disabled 属性) PASS
UE-004 check_send_button_enabled_when_has_content 1. 输入内容;2. 点击发送 消息成功发送到聊天区域,输入框清空 PASS
UE-005 check_send_button_disabled_during_streaming 1. 发送消息;2. 空输入状态下再次点击发送 无重复消息产生(应用通过清空输入框自然防止流式期间的重复发送) PASS
UE-006 check_editor_fixed_size_with_short_message 1. 记录初始高度;2. 输入短消息;3. 再次获取高度 短消息输入前后 offsetHeight 均为 80px(固定高度) PASS
UE-007 check_editor_scrollbar_for_long_message 1. 输入 2003 字长文本;2. 检查 scrollHeight / clientHeight scrollHeight 599px >> clientHeight 80px;滚动功能正常 PASS
UE-008 check_word_count_display_when_empty 1. 创建会话;2. 检查 #char-count 元素文本 显示 “0/2000”(注:实际 DOM 为 #char-count,非 .word-count) PASS
UE-009 check_word_count_realtime_update 1. 输入 “123”;2. 检查字数;3. 追加 “456789”;4. 再次检查 第一次 “3/2000”;第二次 “9/2000”(字数实时更新) PASS
UE-010 check_word_count_limit 1. 通过 JS 设置 value 为 2000 字符;2. 检查显示;3. 尝试追加字符 显示 “2000/2000”;追加被 textarea maxlength=“2000” 原生阻止 PASS

关键代码:

class UserInputEditor:
    INPUT_TEXTAREA = (By.ID, "message-input")
    SEND_BUTTON = (By.CSS_SELECTOR, "#send-btn")
    WORD_COUNT_DISPLAY = (By.ID, "char-count")  # API doc said .word-count

    def check_word_count_realtime_update(self):
        """Verify word count updates in real time as user types."""
        self._clear_and_input("123")
        count = self.driver.find_element(*self.WORD_COUNT_DISPLAY).text
        assert count == "3/2000"
        self._clear_and_input("123456789")
        count = self.driver.find_element(*self.WORD_COUNT_DISPLAY).text
        assert count == "9/2000"

    def check_word_count_limit(self):
        """Verify char count reaches 2000 and maxlength blocks excess."""
        long_text = "x" * 2000
        self.driver.execute_script(
            f"arguments[0].value = '{long_text}';", textarea)
        count = self.driver.find_element(*self.WORD_COUNT_DISPLAY).text
        assert count == "2000/2000"
        # Native maxlength prevents further input

七、自动化测试

7.1 自动化测试用例清单

本项目的 UI 自动化测试基于 Page Object Model (POM) 设计模式,共编写 5 个 Page 类,38 个测试方法,全部通过。

脚本文件 Page 类 方法数 通过
test/DefaultInterface.py DefaultAIChat 3 3
test/ModelSelection.py ModelSelection 7 7
test/HistorySessionList.py HistorySessionList 10 10
test/ChatMessageDisplay.py ChatMessageDisplay 8 8
test/UserInputEditor.py UserInputEditor 10 10
test/Main.py —(测试入口) 5 个辅助函数
common/Utils.py Driver / AIChatDriver 单例 + 截图

7.2 自动化框架架构

Main.py (测试入口,整合调度)
   │
   ├── DefaultAIChat     # 页面加载 + 默认界面校验
   ├── ModelSelection    # 模型弹窗校验与选择
   ├── HistorySessionList # 会话列表交互验证
   ├── ChatMessageDisplay # 聊天消息显示验证
   └── UserInputEditor   # 输入框功能验证
        │
        └── Utils.py (AIChatDriver)  # 单例 WebDriver + 自动截图

框架特点:

  • 单例驱动Driver 类使用 __new__ 确保全局唯一 WebDriver 实例,避免重复启动浏览器
  • 显式等待:使用 WebDriverWait + expected_conditions 替代 time.sleep,提高测试稳定性
  • 自动截图:每个测试方法调用 AIChatDriver.getScreenShot() 自动保存截图到 image/日期/ 目录(基于 __file__ 的绝对路径,不依赖 CWD)
  • 异常容错:关键操作使用 try...except 包裹,失败时打印错误信息并截图

7.3 核心工具代码

# common/Utils.py — WebDriver 单例 + 自动截图
class Driver:
    driver = ""

    def __new__(cls, *args, **kwargs):
        if cls.driver == "":
            cls.driver = webdriver.Chrome(service=ChromeService(
                ChromeDriverManager().install()))
        return super().__new__(cls)

    def getScreenShot(self):
        _project_root = os.path.dirname(os.path.dirname(
            os.path.abspath(__file__)))
        image_dir = os.path.join(_project_root, "image",
            datetime.datetime.now().strftime("%Y-%m-%d"))
        if not os.path.exists(image_dir):
            os.makedirs(image_dir)
        filename = sys._getframe().f_back.f_code.co_name + \
            datetime.datetime.now().strftime("%Y-%m-%d-%H%M%S") + ".png"
        self.driver.save_screenshot(os.path.join(image_dir, filename))

7.4 测试执行方式

# 设置目标 URL 环境变量
$env:AI_CHAT_URL = "http://<server-address>:8080/"

# 运行测试入口(各模块测试默认注释,按需取消注释)
python test/Main.py

7.5 截图文件清单

测试期间共生成约 38 张截图,存储在 image/2026-05-09/image/2026-05-10/ 目录下,命名格式为 {方法名}{时间戳}.png,完整覆盖全部 38 个方法的执行结果。


八、项目测试 Bug 简述

8.1 Bug 优先级统计

本次 UI 自动化测试共发现并修复 17 个问题,其中:

优先级 数量 说明
P0(崩溃级) 0 无系统崩溃、功能完全不可用、数据丢失等严重问题
P1(严重级) 5 核心功能异常、定位器错误导致测试失败或假通过
P2(一般级) 8 等待策略、属性理解、定位器命名、路径配置等问题
P3(轻微级) 4 编码兼容、拼写错误、截图遗漏等问题

8.2 Bug 详情列表

Bug 标题 所属模块 优先级 是否修复 备注
CSS 类名 .message.assistant 不匹配,实际为 .message.ai ChatMessageDisplay P1 ✅ 已修复 导致消息区域全部定位失败
头像定位错误:div 而非内部的 img 标签 ChatMessageDisplay P1 ✅ 已修复 .message-avatar 容器内 img 才是头像元素
verify_new_session_displays_new_chat 取错会话项(items[-1] 应为 items[0]) HistorySessionList P1 ✅ 已修复 列表降序排列,取最后一项得到最老会话
verify_session_time_updates_after_message 未点击目标会话导致发送失败 HistorySessionList P1 ✅ 已修复 输入区未加载,发送失败被 try 捕获,造成假 PASS
os.mkdir 无法创建多级截图目录,导致新日期截图保存失败 Utils.py P1 ✅ 已修复 改用 os.makedirs 递归创建
流式回复等待策略失效(轮询检测不到稳定状态) ChatMessageDisplay P2 ✅ 已修复 改为"等消息 DOM 出现 + 固定等待"策略
代码块 DOM 持续更新导致 StaleElementException ChatMessageDisplay P2 ✅ 已修复 改用 execute_script 操作元素
r1 思考过程触发不稳定,简单提示词无思考内容 ChatMessageDisplay P2 ✅ 已修复 toggle 测试增加容错跳过逻辑
placeholder 为静态 HTML 属性,输入后不会清空 UserInputEditor P2 ✅ 已修复 改为验证 value 属性而非 placeholder 变化
发送按钮无 DOM 级 disabled 属性 UserInputEditor P2 ✅ 已修复 确认应用通过逻辑层 + 清空输入框阻止空发送
字数统计定位器 .word-count 实际 DOM 为 #char-count UserInputEditor P2 ✅ 已修复 API 文档选择器与 DOM 不一致
ChromeDriver 每次启动需联网下载 UserInputEditor P2 ✅ 已修复 配置优先使用本地缓存
截图路径使用相对路径,依赖 CWD Utils.py P2 ✅ 已修复 改为基于 file 的绝对路径
Windows GBK 终端编码不兼容 ✅/✓ 等 Unicode 字符 ChatMessageDisplay P3 ✅ 已修复 全部替换为 [PASS]/[OK]
方法名拼写错误:elementExsit → elementExists ModelSelection / Main.py P3 ✅ 已修复 同步修正 4 个文件
chooseDeepSeek/chooseDeepSeekR1/chooseGemini/chooseGPT 缺少截图 ModelSelection P3 ✅ 已修复 4 个方法各补全 AIChatDriver.getScreenShot()
ClickNewSession 缺少截图 DefaultInterface P3 ✅ 已修复 方法末尾补全截图调用

九、遗留问题

9.1 未覆盖的测试类型

类型 说明 计划
跨浏览器测试 仅在 Chrome 147 执行,未覆盖 Firefox、Edge 等 根据实际用户浏览器分布决定是否补充

9.2 已知限制

  1. R1 思考过程触发不稳定:简单提示词(如"你好")不会触发 r1 模型的思考过程,测试中通过调整提示词复杂度来触发,非功能缺陷。
  2. 发送按钮无 HTML disabled 属性:应用通过 JavaScript 逻辑层控制发送行为(清空输入框 + 阻止空消息),而非设置按钮的 disabled 属性。这是设计选择,非 Bug。
  3. placeholder 为静态属性:HTML textarea 的 placeholder 属性在输入后不会自动清空(浏览器原生行为),视觉上由浏览器自动隐藏。测试调整为验证 value 属性。

十、测试结论

10.1 整体测试结果

本次项目测试:通过 ✅(UI 自动化 38/38 全部 PASS)⚠️(性能测试发现 2 个 P0 服务端缺陷)

UI 自动化:核心功能模块均验证通过,38 个测试方法全部 PASS。无 P0 级遗留问题,5 个 P1 级问题均已修复完成,12 个 P2/P3 级问题已记录并修复。

性能测试:发现服务端并发上限为 5 用户,10+ 并发发生 segfault 崩溃(P0),无效 session_id 触发崩溃(P0)。

10.2 耗时统计

阶段 耗时 说明
UI 测试开发 约 2 天 5 个测试模块代码编写
ChatMessageDisplay 测试 + 修复 1 天 8 个方法,修复 6 个问题
UserInputEditor 测试 + 修复 1 天 10 个方法,修复 4 个问题
三模块补全 + 回归 1 天 DefaultInterface / ModelSelection / HistorySessionList
JMeter 环境搭建与调试 2h 插件兼容性修复 × 5 次迭代
Scene 1 基准测试 30min 1 用户 × 6 API
Scene 2 负载测试 1h 5→10→20 阶梯(两次运行,服务端崩溃重启)
Scene 5 混合场景 1h 5 用户完整链路(4 次迭代,守卫完善)
合计测试耗时 约 5 天 含开发、测试、修复、性能分析

10.3 项目补充信息

项目信息 详情
项目框架 前端:原生 HTML/CSS/JS;后端:C++ httplib
测试框架 Python 3.12 + Selenium 4.43 + JMeter 5.6.3
设计模式 Page Object Model (POM)
浏览器 Google Chrome 147
测试目标 http://<server-address>:8080/
代码仓库(测试) git@gitee.com:holychanges/AIChatServer_AutoTest.git
代码仓库(后端) https://gitee.com/BearOnToilet/ai-based-chat-assistant.git
测试环境 开发/测试环境,无线上用户

10.4 测试总结与优化建议

  1. 修复服务端并发崩溃(P0):httplib 替换为支持高并发的方案(连接池/多进程/nginx 反向代理)
  2. 修复无效 session 崩溃(P0):SQL 查询结果做空值检查,返回 404 而非 segfault
  3. 接入 Pytest:将当前脚本式测试迁移至 Pytest 框架,获得更规范的用例管理、参数化和测试报告
  4. 补充接口自动化测试:后端 API 文档已具备(RequestTXT/api.txt,7 个端点),可编写 Pytest 接口测试
  5. CI/CD 集成:将自动化测试接入持续集成流水线,实现代码提交自动触发测试

十一、API 性能测试

11.1 测试场景与结果

场景 并发 模式 请求数 错误率 平均响应 结果
Scene 1 基准 1 6 API 顺序 × 10 轮 60 0% 1.7s
Scene 2 Phase 1 5 GET /api/sessions 轮询 8,228 0% 188ms
Scene 2 Phase 2 10 GET /api/sessions 轮询 7,144 3.1%→恶化 205ms ⚠️
Scene 2 Phase 3 20 GET /api/sessions 轮询 ❌ segfault
Scene 5 v1 (无守卫) 5 完整链路 458 25.8% 3.5s ⚠️
Scene 5 v4 (有守卫) 5 完整链路 + If Controller 253 47.8% 6.3s ⚠️ 断言误判 + GET/sessions 超时

47.8%和无响应错误率来自 GET /api/sessions 全部超时

11.2 并发上限

  1 用户   ✅ 稳定
  5 用户   ✅ 纯查询稳定 / ⚠️ 混合链路有退化
 10 用户   ⚠️ 临界,随时间恶化
 20 用户   ❌ 服务器崩溃

生产环境安全并发建议:5 用户以内。

11.3 混合场景 v4 明细(5 用户 + If Controller 守卫)

API 请求 通过 错误率 平均 说明
POST /api/session 113 113 0% 7.4s ✅ 全部成功(断言误判为 35 通过)
POST /api/message 35¹ 35 0% 7.1s ✅ 有效 session 消息全部成功
GET /api/session/{id}/history 35¹ 32 8.6% 1.8s ✅ 基本正常
GET /api/sessions 35¹ 0 100% 10.1s ❌ 全部超时,数据库查询瓶颈
DELETE /api/session/{id} 35¹ 30 14.3% 2.5s ✅ 基本正常

¹ 下游仅执行 35 次是因为 JMeter Response Assertion (test_type=8 Equals) 误判了 78 次 CreateSession 为失败,If Controller 拦截了这些请求。CreateSession 实际 HTTP 200 全部成功。

11.4 发现的服务端缺陷

# 问题 严重度 表现
1 并发 > 10 时 segfault 崩溃 P0 httplib 连接池耗尽,C++ 进程崩溃
2 无效 session_id 触发崩溃 P0 SQL 查询失败未防御性处理
3 GET /api/sessions 并发性能极差 P1 5 并发下全部超时(>10s)
4 资源随时间累积退化 P1 运行 5+ 分钟后低并发也超时

11.5 JMeter 兼容性问题与解决

# 问题 解决方案
1 SteppingThreadGroup (jp@gc) 不兼容 JMeter 5.6.3 改用 ConcurrencyThreadGroup (bzm)
2 普通 ThreadGroup + duration 不执行采样器 改用 ConcurrencyThreadGroup
3 TransactionControllerConcurrencyThreadGroup 冲突 去掉 TransactionController
4 断言 &quot; 实体编码匹配失败 仅校验 Response Code = 200
5 If Controller 类名 com.blazemeter.* 不存在 改为 org.apache.jmeter.control.IfController
6 Response Assertion test_type=8 (Equals) 误判 HTTP 200 改用 test_type=2 (Contains) 检查响应体 "success" 或仅用 Response Code 子串匹配

11.6 相关文件

文件 路径
性能测试方案 doc/performance_test_plan.txt
主测试计划 doc/AI_Chat_API_Performance_Test.jmx
负载测试 doc/AI_Chat_API_Load_Test_Scene2.jmx
混合场景(含守卫) doc/AI_Chat_API_Mixed_Scene5.jmx
GUI 手动操作指南 doc/JMeter_GUI_Step_by_Step.txt
后端 API 文档 AIModelAccessTech/ChatServer/RequestTXT/api.txt(后端仓库)

|(注:本文档由测试数据自动汇总生成)

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐