【AI智能聊天助手-网页版】测试报告
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 自动化测试,对系统各核心页面进行功能验证,确保界面元素、交互逻辑和业务流程的正确性与稳定性。
二、项目简介
本系统包含以下核心功能模块:
-
默认界面(DefaultInterface):系统首页,包含左侧导航栏(AI 图标、"AI聊天助手"标题、新建对话按钮)和右侧欢迎页(引导文案、新建对话入口)。
-
模型选择(ModelSelection):新建对话时弹出模型选择窗口,展示 4 个可选模型(deepseek-chat、deepseek-r1:1.5b、gemini-3.1-flash-lite-preview、gpt-4o-mini),支持确认创建或取消操作。
-
历史会话列表(HistorySessionList):左侧会话列表,按时间降序排列,展示会话时间、消息预览、模型标签,支持会话切换、悬停删除、滚动浏览等功能。
-
聊天消息显示(ChatMessageDisplay):聊天区域核心模块,包含模型名称展示、消息气泡(AI/用户)、思考过程面板(r1 模型)、Markdown 表格渲染、代码块语法高亮与复制等功能。
-
用户输入编辑器(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 已知限制
- R1 思考过程触发不稳定:简单提示词(如"你好")不会触发 r1 模型的思考过程,测试中通过调整提示词复杂度来触发,非功能缺陷。
- 发送按钮无 HTML disabled 属性:应用通过 JavaScript 逻辑层控制发送行为(清空输入框 + 阻止空消息),而非设置按钮的
disabled属性。这是设计选择,非 Bug。 - 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 测试总结与优化建议
- 修复服务端并发崩溃(P0):httplib 替换为支持高并发的方案(连接池/多进程/nginx 反向代理)
- 修复无效 session 崩溃(P0):SQL 查询结果做空值检查,返回 404 而非 segfault
- 接入 Pytest:将当前脚本式测试迁移至 Pytest 框架,获得更规范的用例管理、参数化和测试报告
- 补充接口自动化测试:后端 API 文档已具备(
RequestTXT/api.txt,7 个端点),可编写 Pytest 接口测试 - 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 | TransactionController 与 ConcurrencyThreadGroup 冲突 |
去掉 TransactionController |
| 4 | 断言 " 实体编码匹配失败 |
仅校验 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(后端仓库) |
|(注:本文档由测试数据自动汇总生成)
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)