论坛项目测试文档

1. 项目背景

在当今数字化信息交流日益频繁的时代,论坛作为一种重要的在线交流平台,为用户提供了信息分享、知识交流和互动讨论的空间。本论坛系统基于Spring技术框架进行开发,采用前后端分离的架构模式,打造了一个功能丰富、高效稳定且易于使用的在线交流社区。
前后端分离架构使得前端专注于用户界面的呈现和交互,后端负责业务逻辑处理和数据存储,结合MySQL数据库进行数据管理,利用Maven进行项目构建,Git和Gitee进行版本控制。
在技术选型上,后端运用Spring、Spring Boot、Spring MVC和MyBatis等技术,来进行业务逻辑处理;前端则采用HTML、CSS、JavaScript、jQuery和Bootstrap等技术,构建美观且交互友好的用户界面。


2. 项目功能

用户管理功能

  1. 注册登录:用户注册时需提供用户名、昵称、密码等信息。系统会对注册信息进行校验,如检查用户名是否已存在,密码与确认密码是否一致等。注册成功后,用户可用注册的账号登录系统。
  2. 个人中心:用户可在个人中心查看个人资料,包含用户名、昵称、性别等信息。支持修改部分个人信息,如昵称、性别、邮箱,但密码和头像修改需通过单独的接口进行。此外,用户还能在个人中心查看自己的发帖数量及历史帖子。
  3. 修改密码:在个人中心,用户可通过输入原密码、新密码和确认新密码来修改密码。系统会对原密码的正确性以及新密码与确认新密码的一致性进行校验。

版块管理功能

  1. 添加版块:管理员负责添加版块,添加时需提供版块名称和排序信息。版块信息包括版块名、帖子数量、排序优先级、状态等。添加成功后,版块将在论坛中展示。
  2. 获取版块信息:支持根据版块Id获取指定版块的详细信息,如版块名、帖子数量等。还可获取在首页显示的版块信息,这些信息支持按排序字段排序,且可控制首页展示的版块个数。

帖子管理功能

  1. 帖子列表展示:分为版块帖子列表和用户帖子列表。版块帖子列表根据用户点击的版块或首页请求,按发布时间降序展示对应版块的帖子;用户帖子列表则在用户详情页按发布时间降序展示当前用户发布的帖子。
  2. 帖子操作:用户可对帖子进行发布、编辑、删除、点赞等操作。发布帖子时,需选择版块、填写标题和正文,系统会校验相关信息,并更新用户和版块的帖子数量;编辑帖子时,用户仅能编辑自己发布的帖子,提交时系统会进行校验;删除帖子时,服务器会校验用户状态、帖子状态以及当前用户是否为作者;点赞帖子时,用户在帖子详情页点击点赞按钮,系统会更新帖子的点赞数。
  3. 获取帖子详情:当用户点击帖子时,服务器会根据帖子Id查询帖子信息,并将访问次数加1,返回帖子详情,包含标题、正文、访问次数、回复次数等信息。

回复管理功能

  1. 提交回复内容:在帖子详情页面,用户可填写回复内容并提交。服务器会校验回复内容、帖子与用户状态,校验通过后将回复内容写入数据库,并增加帖子的回复数量。
  2. 帖子回复列表:在帖子详情页,以发布时间降序排列显示当前帖子下的回复列表,其中包含回复内容、回复者信息等。

3. 测试计划

3.1 测试用例设计

3.2 功能测试

3.2.1 测试用例

3.2.2 实际测试的部分重要功能截图

  1. 登录

    在登录界面会对用户名框以及密码框进行判空检查,但没有字符长度以及特殊字符限制;密码遮盖功能正常;登陆成功后会跳转到论坛页面,失败则正确弹出错误提示。
  2. 注册

    若是新用户,可通过登录页面进行注册跳转;同样,在注册界面也有判空检查,也没有字符长度以及特殊字符限制;密码遮盖功能正常;注册成功后会跳转到登录页面,失败则正确弹出错误提示。
  3. 主界面

    主界面抓取帖子列表正常,帖子显示分类正常,用户信息显示正常。
  4. 用户中心

    点击用户头像可进入用户中心,在用户中心可以对昵称,用户名,邮箱,手机以及密码等进行修改; 但修改头像功能没有完善,无法进行修改;在修改密码时需正确提供原密码与两次校验一致的新密码,否则弹出错误提示;但对用户名,昵称,电话等没有设置正确的长度限制以及特殊字符限制。
  5. 发布帖子

    通过点击主页‘发布帖子’可以在论坛发送markdown格式的文章博客;模块,标题,内容等经过测试都显示正常;发布按钮正常可用;发布文章显示在正确的分类页。
  6. 查看帖子

    贴子正确显示在主页上。 但是点击查看后却发现图片没有正确显示,帖子似乎不支持该写法。 使用帖子内置的图片上传功能后,查看帖子发现可以正常显示,链接可以正常跳转;浏览量,点赞,回复等都能正确统计,正确显示。 点赞和回复后,统计正确显示。

3.3 自动化测试

采用Python+selenium库进行自动化脚本编写。

3.3.1 登录测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.edge.service import Service
from webdriver_manager.microsoft import EdgeChromiumDriverManager

# 定义测试数据
correct_username = "chengzi"
correct_password = "123456"
wrong_username = "zhangsan"
wrong_password = "123"

# 初始化 Edge 浏览器驱动
driver = webdriver.Edge(service=Service(EdgeChromiumDriverManager().install()))

try:
# 打开登录页面
driver.get("http://127.0.0.1:9580/sign-in.html")

# 测试用例 1:正确用户名和密码能否成功登录
username_input = driver.find_element(By.ID, "username")
password_input = driver.find_element(By.ID, "password")
submit_button = driver.find_element(By.ID, "submit")

username_input.send_keys(correct_username)
password_input.send_keys(correct_password)
submit_button.click()
time.sleep(2) # 等待页面加载

# 这里可以根据登录成功后的页面元素进行判断,例如页面标题、特定元素的存在等
# 假设登录成功后页面标题会改变
# 获取页面标题
page_title = driver.title
print(page_title) # 输出:比特论坛 - 用户登录 但实际的测试项目title登入后仍然是比特论坛,此时可以考虑抓取页面元素来判定
if driver.title != "比特论坛 - 用户登录":
print("测试用例 1:正确用户名和密码登录成功")
else:
print("测试用例 1:正确用户名和密码登录失败")

# 返回到登录页面
driver.back()
time.sleep(2)

# 测试用例 2:错误用户名或密码是否可以登入
username_input.clear()
password_input.clear()

username_input.send_keys(wrong_username)
password_input.send_keys(wrong_password)
submit_button.click()
time.sleep(2)

# 这里可以根据实际的错误提示元素进行判断
# 假设错误提示会显示在某个元素中
error_message = driver.find_element(By.CSS_SELECTOR, "body > div.jq-toast-wrap.bottom-right > div > h2").text
if "警告" in error_message:
print("测试用例 2:错误用户或密码无法登入")
else:
print("测试用例 2:测试失败!")

# 测试用例 3:密码输入框是否支持密码显示/隐藏功能
password_show_hide_button = driver.find_element(By.ID, "password_a")
password_input = driver.find_element(By.ID, "password")

# 检查初始状态为密码隐藏
if password_input.get_attribute("type") == "password":
print("初始状态:密码隐藏")
else:
print("初始状态:密码未隐藏,测试失败")

# 点击显示密码按钮
password_show_hide_button.click()
time.sleep(1)

# 检查点击后密码是否显示
if password_input.get_attribute("type") == "text":
print("点击后:密码显示")
else:
print("点击后:密码未显示,测试失败")

# 再次点击隐藏密码
password_show_hide_button.click()
time.sleep(1)

# 检查再次点击后密码是否隐藏
if password_input.get_attribute("type") == "password":
print("再次点击后:密码隐藏")
else:
print("再次点击后:密码未隐藏,测试失败")

# 测试用例 4:“记住密码”功能是否有效,下次打开是否自动填充
# 由于 HTML 代码中“记住密码”功能被注释掉,这里仅提供思路
# 若存在该功能,可先勾选“记住密码”,输入用户名和密码登录,
# 然后关闭浏览器,重新打开登录页面,检查用户名和密码是否自动填充

except Exception as e:
print(f"测试过程中出现错误:{e}")
finally:
# 关闭浏览器
driver.quit()

3.3.2 注册测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.edge.service import Service
from selenium.common.exceptions import NoSuchElementException
from webdriver_manager.microsoft import EdgeChromiumDriverManager

# 初始化 Edge 浏览器驱动
driver = webdriver.Edge(service=Service(EdgeChromiumDriverManager().install()))

try:
# 打开注册页面
driver.get("http://127.0.0.1:9580/sign-up.html")

# 测试用例 1:必填项未填是否有提示
submit_button = driver.find_element(By.ID, "submit")
submit_button.click()
time.sleep(2)

required_fields = ["username", "nickname", "password", "passwordRepeat"]
for field in required_fields:
try:
error_element = driver.find_element(By.CSS_SELECTOR, f"#{field} + .invalid-feedback") #+ 是 CSS 中的相邻兄弟选择器。它的作用是选择紧跟在某个元素后面的同级元素。
if error_element.is_displayed():
print(f"测试用例 1:{field} 未填,提示显示正常")
else:
print(f"测试用例 1:{field} 未填,提示未显示")
except NoSuchElementException:
print(f"测试用例 1:未找到 {field} 的错误提示元素")

# 测试用例 2:用户名是否支持特殊字符,长度限制是否合理
special_char_username = "!@#$%^&*()"
short_username = "a"
long_username = "a" * 50

username_input = driver.find_element(By.ID, "username")
username_input.send_keys(special_char_username)
submit_button.click()
time.sleep(2)
try:
error_element = driver.find_element(By.CSS_SELECTOR, "#username + .invalid-feedback")
if error_element.is_displayed():
print("测试用例 2:用户名包含特殊字符,提示显示正常")
else:
print("测试用例 2:用户名包含特殊字符,提示未显示")
except NoSuchElementException:
print("测试用例 2:未找到用户名包含特殊字符的错误提示元素")

username_input.clear()
username_input.send_keys(short_username)
submit_button.click()
time.sleep(2)
try:
error_element = driver.find_element(By.CSS_SELECTOR, "#username + .invalid-feedback")
if error_element.is_displayed():
print("测试用例 2:用户名过短,提示显示正常")
else:
print("测试用例 2:用户名过短,提示未显示")
except NoSuchElementException:
print("测试用例 2:未找到用户名过短的错误提示元素")

username_input.clear()
username_input.send_keys(long_username)
submit_button.click()
time.sleep(2)
try:
error_element = driver.find_element(By.CSS_SELECTOR, "#username + .invalid-feedback")
if error_element.is_displayed():
print("测试用例 2:用户名过长,提示显示正常")
else:
print("测试用例 2:用户名过长,提示未显示")
except NoSuchElementException:
print("测试用例 2:未找到用户名过长的错误提示元素")

# 测试用例 3:重复用户名注册是否有提示
# 假设已经有一个用户名为 "existing_user" 的用户
existing_username = "chengzi"
username_input.clear()
username_input.send_keys(existing_username)
submit_button.click()
time.sleep(2)
try:
error_element = driver.find_element(By.CSS_SELECTOR, "#username + .invalid-feedback")
if error_element.is_displayed():
print("测试用例 3:重复用户名注册,提示显示正常")
else:
print("测试用例 3:重复用户名注册,提示未显示")
except NoSuchElementException:
print("测试用例 3:未找到重复用户名的错误提示元素")

# 测试用例 4:密码强度检测(如包含字母、数字、特殊字符等)
weak_password = "123456"
strong_password = "Abc123!"

password_input = driver.find_element(By.ID, "password")
password_repeat_input = driver.find_element(By.ID, "passwordRepeat")

password_input.send_keys(weak_password)
password_repeat_input.send_keys(weak_password)
submit_button.click()
time.sleep(2)
try:
error_element = driver.find_element(By.CSS_SELECTOR, "#password + .invalid-feedback")
if error_element.is_displayed():
print("测试用例 4:弱密码,提示显示正常")
else:
print("测试用例 4:弱密码,提示未显示")
except NoSuchElementException:
print("测试用例 4:未找到弱密码的错误提示元素")

password_input.clear()
password_repeat_input.clear()
password_input.send_keys(strong_password)
password_repeat_input.send_keys(strong_password)
submit_button.click()
time.sleep(2)
try:
error_element = driver.find_element(By.CSS_SELECTOR, "#password + .invalid-feedback")
if not error_element.is_displayed():
print("测试用例 4:强密码,无错误提示")
else:
print("测试用例 4:强密码,出现错误提示")
except NoSuchElementException:
print("测试用例 4:强密码,无错误提示元素")

# 测试用例 5:同意条款未勾选能否注册成功
submit_button.click()
time.sleep(2)
try:
# 这里可以根据实际情况判断注册是否成功,比如页面是否跳转等
if driver.current_url == "http://127.0.0.1:9580/sign-up.html":
print("测试用例 5:同意条款未勾选,注册未成功")
else:
print("测试用例 5:同意条款未勾选,注册成功,存在问题")
except Exception as e:
print(f"测试用例 5:判断注册结果时出现错误:{e}")

except Exception as e:
print(f"测试过程中出现错误:{e}")
finally:
# 关闭浏览器
driver.quit()

3.3.3 发布帖子测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.edge.service import Service
from webdriver_manager.microsoft import EdgeChromiumDriverManager
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import NoSuchElementException


def login():
try:
# 打开页面
driver.get("http://127.0.0.1:9580/sign-in.html")
username = "chengzi" # 替换为实际的用户名
password = "123456" # 替换为实际的密码

# 定位用户名输入框并输入用户名
username_input = driver.find_element(By.ID, "username")
username_input.send_keys(username)

# 定位密码输入框并输入密码
password_input = driver.find_element(By.ID, "password")
password_input.send_keys(password)

# 定位登录按钮并点击
login_button = driver.find_element(By.ID, "submit")
login_button.click()

except Exception as e:
print(f"登录出错: {e}")


def test_post_creation():
try:
# 点击发帖按钮
issue_button = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.CSS_SELECTOR, "#bit-forum-content > div.page-header.d-print-none > div > div > div.col-auto.ms-auto.d-print-none > div > a.btn.btn-primary.d-none.d-sm-inline-block.article_post"))
)
driver.execute_script("arguments[0].click();", issue_button)

# 等待页面加载
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "article_post_borad"))
)

# 选择版块,这里选择第一个版块(JAVA)
board_select = driver.find_element(By.ID, "article_post_borad")
board_select.find_element(By.CSS_SELECTOR, 'option[value="1"]').click()

# 输入标题
title_input = driver.find_element(By.ID, "article_post_title")
title_input.send_keys("测试帖子标题")

# 输入内容
# 等待编辑器加载完成
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, ".editormd"))
)

# 使用 JavaScript 直接设置内容
content_textarea = driver.find_element(By.ID, "article_post_content")
driver.execute_script("arguments[0].value = '测试帖子内容';", content_textarea)

# 点击发布按钮
submit_button = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.ID, "article_post_submit"))
)
driver.execute_script("arguments[0].click();", submit_button)
time.sleep(3)

# 等待提示信息出现
WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.CSS_SELECTOR, ".jq-toast-single.jq-has-icon.jq-icon-success"))
)

# 获取提示信息的文本内容
toast_message = driver.find_element(By.CSS_SELECTOR, '.jq-toast-single.jq-has-icon.jq-icon-success').text
message_text = toast_message.strip() # 使用strip()去除多余空格

# 判断是否发布成功
if "发帖成功" in message_text:
print("帖子发布成功")
else:
print(f"帖子发布失败,提示信息:{message_text}")

except Exception as e:
print(f"测试过程中出现错误:{e}")


def test_empty_title():
try:
# 点击发帖按钮
issue_button = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.CSS_SELECTOR, "#bit-forum-content > div.page-header.d-print-none > div > div > div.col-auto.ms-auto.d-print-none > div > a.btn.btn-primary.d-none.d-sm-inline-block.article_post"))
)
driver.execute_script("arguments[0].click();", issue_button)

# 等待页面加载
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "article_post_borad"))
)

# 选择版块,这里选择第一个版块(JAVA)
board_select = driver.find_element(By.ID, "article_post_borad")
board_select.find_element(By.CSS_SELECTOR, 'option[value="1"]').click()
#输入标题但不输入内容
title_input = driver.find_element(By.ID, "article_post_title").send_keys("测试用标题")
submit_button = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.ID, "article_post_submit"))
)
driver.execute_script("arguments[0].click();", submit_button)
time.sleep(3)

# 等待错误提示信息出现
WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.CSS_SELECTOR, ".jq-toast-single.jq-has-icon.jq-icon-warning"))
)

# 获取错误提示信息的文本内容
error_message = driver.find_element(By.CSS_SELECTOR, '.jq-toast-single.jq-has-icon.jq-icon-warning').text
error_text = error_message.strip()

# 判断是否提示标题不能为空
if "请输入帖子内容" in error_text:
print("测试用例通过:内容为空时提示正确")
else:
print(f"测试用例失败:未找到正确的提示信息,实际内容为:'{error_text}'")


except Exception as e:
print(f"测试过程中出现错误:{e}")

def test_empty_content():
try:
# 不输入标题
title_input = driver.find_element(By.ID, "article_post_title")
title_input.clear() # 清空标题

# 输入内容
content_textarea = driver.find_element(By.ID, "article_post_content")
driver.execute_script("arguments[0].value = '测试帖子内容';", content_textarea)

# 点击发布按钮
submit_button = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.ID, "article_post_submit"))
)
driver.execute_script("arguments[0].click();", submit_button)
time.sleep(3)

# 等待错误提示信息出现
WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.CSS_SELECTOR, ".jq-toast-single.jq-has-icon.jq-icon-warning"))
)

# 获取错误提示信息的文本内容
error_message = driver.find_element(By.CSS_SELECTOR, '.jq-toast-single.jq-has-icon.jq-icon-warning').text
error_text = error_message.strip()

# 判断是否提示标题不能为空
if "请输入帖子标题" in error_text:
print("测试用例通过:标题为空时提示正确")
else:
print(f"测试用例失败:未找到正确的提示信息,实际内容为:'{error_text}'")
except Exception as e:
print(f"测试过程中出现错误:{e}")

def test_reply_to_post():
try:
# 找到刚刚发布的帖子并点击进入
post_link = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.CSS_SELECTOR, "a.article_list_a_title"))
)
post_link.click()

# 等待回复框加载完成
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "article_details_reply"))
)

# 定位与编辑器关联的隐藏textarea并输入回复内容
reply_textarea = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "details_article_reply_content"))
)
driver.execute_script("arguments[0].value = '这是一个测试回复';", reply_textarea)

# 定位回复按钮
reply_button = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.ID, "details_btn_article_reply"))
)
# 滚动到回复按钮位置
driver.execute_script("arguments[0].scrollIntoView();", reply_button)
time.sleep(1) # 等待滚动完成

# 点击回复按钮
driver.execute_script("arguments[0].click();", reply_button)
time.sleep(3)

# 等待回复成功提示信息出现
WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.CSS_SELECTOR, ".jq-toast-single.jq-has-icon.jq-icon-success"))
)

# 获取回复成功提示信息的文本内容
success_message = driver.find_element(By.CSS_SELECTOR, '.jq-toast-single.jq-has-icon.jq-icon-success').text
success_text = success_message.strip()

# 判断是否提示回复成功
if "回复成功" in success_text:
print("测试用例通过:回复成功")
else:
print(f"测试用例失败:未找到正确的提示信息,实际内容为:'{success_text}'")
except Exception as e:
print(f"测试过程中出现错误:{e}")


if __name__ == "__main__":
# 初始化 Edge 浏览器驱动
driver = webdriver.Edge(service=Service(EdgeChromiumDriverManager().install()))
login()
time.sleep(8)

# 测试标题或内容为空时的提示
test_empty_title()
time.sleep(3)
test_empty_content()

index_button = driver.find_element(By.CSS_SELECTOR,"#nav_board_index > a > span.nav-link-title").click()
# 测试发布帖子
test_post_creation()

# 测试回复帖子
test_reply_to_post()

# 关闭浏览器
driver.quit()

3.3.4 查看帖子测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.edge.service import Service
from webdriver_manager.microsoft import EdgeChromiumDriverManager
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


# 初始化Edge浏览器驱动
driver = webdriver.Edge(service=Service(EdgeChromiumDriverManager().install()))


def login():
try:
# 打开页面
driver.get("http://127.0.0.1:9580/sign-in.html")
username = "chengzi" # 替换为实际的用户名
password = "123456" # 替换为实际的密码
# 定位用户名输入框并输入用户名
username_input = driver.find_element(By.ID, "username")
username_input.send_keys(username)
# 定位密码输入框并输入密码
password_input = driver.find_element(By.ID, "password")
password_input.send_keys(password)
# 定位登录按钮并点击
login_button = driver.find_element(By.ID, "submit")
login_button.click()
except Exception as e:
print(f"登录出错: {e}")


def check_post_content_display():
try:
blog_button = driver.find_element(By.CSS_SELECTOR, "a.article_list_a_title")
blog_button.click()
# 等待帖子内容区域加载完成
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "details_article_content"))
)
post_content = driver.find_element(By.ID, "details_article_content")
# 检查图片是否显示
images = post_content.find_elements(By.TAG_NAME, "img")
for image in images:
assert image.is_displayed(), "图片未显示"
# 检查链接是否显示
links = post_content.find_elements(By.TAG_NAME, "a")
for link in links:
assert link.is_displayed(), "链接未显示"
print("帖子内容完整显示,包括图片和链接")
except Exception as e:
print(f"检查帖子内容显示时出错: {e}")


def check_view_count_update():
try:
# 记录初始浏览量
initial_view_count_element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "details_article_visitCount"))
)
initial_view_count_text = initial_view_count_element.text
assert initial_view_count_text.strip() != "", "浏览量元素内容为空"
initial_view_count = int(initial_view_count_text)
# 重新打开页面
driver.back()
login()
# 等待页面加载完成
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, "a.article_list_a_title"))
)
blog_button = driver.find_element(By.CSS_SELECTOR, "a.article_list_a_title")
blog_button.click()
# 等待浏览量元素加载完成并获取内容
new_view_count_element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "details_article_visitCount"))
)
# 增加重试机制
max_retries = 3
retries = 0
while retries < max_retries:
new_view_count_text = new_view_count_element.text
if new_view_count_text.strip() != "":
break
time.sleep(1)
retries += 1
assert new_view_count_text.strip() != "", "浏览量元素内容为空"
new_view_count = int(new_view_count_text)
assert new_view_count == initial_view_count + 1, "浏览量未正确更新"
print("浏览量实时更新正确")
except Exception as e:
print(f"检查浏览量更新时出错: {e}")


def check_like_reply_count_accuracy():
try:
# 记录初始点赞数
initial_like_count_element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "details_article_likeCount"))
)
initial_like_count_text = initial_like_count_element.text
assert initial_like_count_text.strip() != "", "点赞数元素内容为空"
initial_like_count = int(initial_like_count_text)

# 点赞帖子
like_button = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.ID, "details_btn_like_count"))
)
like_button.click()
time.sleep(2) # 等待点赞操作完成,可根据实际情况调整等待时间

# 等待点赞数更新并获取新的点赞数
new_like_count_element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "details_article_likeCount"))
)
# 增加重试机制
max_retries = 3
retries = 0
while retries < max_retries:
new_like_count_text = new_like_count_element.text
if new_like_count_text.strip() != "":
break
time.sleep(1)
retries += 1
assert new_like_count_text.strip() != "", "点赞数元素内容为空"
new_like_count = int(new_like_count_text)

assert new_like_count == initial_like_count + 1, "点赞数未正确更新"
print("点赞数实时更新正确")

# 记录初始回复数
initial_reply_count_element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "details_article_replyCount"))
)
initial_reply_count_text = initial_reply_count_element.text
assert initial_reply_count_text.strip() != "", "回复数元素内容为空"
initial_reply_count = int(initial_reply_count_text)

# 定位回复输入框并输入回复内容
reply_textarea = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "details_article_reply_content"))
)
driver.execute_script("arguments[0].value = '这是一个测试回复';", reply_textarea)

# 定位回复按钮
reply_button = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.ID, "details_btn_article_reply"))
)

# 滚动页面使回复按钮可见
driver.execute_script("arguments[0].scrollIntoView();", reply_button)
time.sleep(1) # 等待滚动完成

# 使用 JavaScript 点击回复按钮
driver.execute_script("arguments[0].click();", reply_button)
time.sleep(3) # 等待回复操作完成,可根据实际情况调整等待时间

# 等待回复数更新并获取新的回复数
new_reply_count_element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "details_article_replyCount"))
)
# 增加重试机制
max_retries = 3
retries = 0
while retries < max_retries:
new_reply_count_text = new_reply_count_element.text
if new_reply_count_text.strip() != "":
break
time.sleep(1)
retries += 1
assert new_reply_count_text.strip() != "", "回复数元素内容为空"
new_reply_count = int(new_reply_count_text)

assert new_reply_count == initial_reply_count + 1, "回复数未正确更新"
print("回复数实时更新正确")
except Exception as e:
print(f"检查点赞、评论、回复数量统计时出错: {e}")


try:
login()
time.sleep(5)
check_post_content_display()
time.sleep(2)
check_view_count_update()
time.sleep(2)
check_like_reply_count_accuracy()
finally:
driver.quit()

3.3.5 用户中心测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.edge.service import Service
from webdriver_manager.microsoft import EdgeChromiumDriverManager
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import NoSuchElementException


# 初始化 Edge 浏览器驱动
driver = webdriver.Edge(service=Service(EdgeChromiumDriverManager().install()))

try:
# 打开页面
driver.get("http://127.0.0.1:9580/sign-in.html")

username = "chengzi" # 替换为实际的用户名
password = "123456" # 替换为实际的密码

# 定位用户名输入框并输入用户名
username_input = driver.find_element(By.ID, "username")
username_input.send_keys(username)

# 定位密码输入框并输入密码
password_input = driver.find_element(By.ID, "password")
password_input.send_keys(password)

# 定位登录按钮并点击
login_button = driver.find_element(By.ID, "submit")
login_button.click()

time.sleep(4)

# 点击用户头像,展开下拉菜单
avatar = driver.find_element(By.ID, "index_nav_avatar")
avatar.click()
time.sleep(2)

# 点击个人中心进入修改页面
personal_center = driver.find_element(By.ID, "index_user_settings")
personal_center.click()
time.sleep(2)

# 测试用例 1:修改头像,不同格式(如 jpg、png)图片能否上传成功
# 假设上传头像的输入框的 id 为 avatar_upload ,因为项目没有完善该功能
# avatar_upload = driver.find_element(By.ID, "avatar_upload")

# 测试 jpg 格式图片上传
'''
jpg_image_path = "./2.jpg"
avatar_upload.send_keys(jpg_image_path)
time.sleep(2)
try:
success_message = driver.find_element(By.ID, "avatar_upload_success")
print("测试用例 1:jpg 图片上传成功")
except NoSuchElementException:
print("测试用例 1:jpg 图片上传失败")

# 测试 png 格式图片上传
png_image_path = "./1.png"
avatar_upload.send_keys(png_image_path)
time.sleep(2)
try:
success_message = driver.find_element(By.ID, "avatar_upload_success")
print("测试用例 1:png 图片上传成功")
except NoSuchElementException:
print("测试用例 1:png 图片上传失败")
'''

# 测试用例 2:修改昵称,长度限制和特殊字符处理
nickname_input = driver.find_element(By.ID, "setting_input_nickname")

# 测试短昵称
short_nickname = "a"
nickname_input.clear()
nickname_input.send_keys(short_nickname)
save_button = driver.find_element(By.ID, "setting_submit_nickname")
save_button.click()
time.sleep(2)
try:
error_message = driver.find_element(By.ID, "nickname_error")
print("测试用例 2:短昵称修改失败,提示正常")
except NoSuchElementException:
print("测试用例 2:短昵称修改成功,可能存在问题")

# 测试长昵称
long_nickname = "a" * 50
nickname_input.clear()
nickname_input.send_keys(long_nickname)
save_button.click()
time.sleep(2)
try:
error_message = driver.find_element(By.ID, "nickname_error")
print("测试用例 2:长昵称修改失败,提示正常")
except NoSuchElementException:
print("测试用例 2:长昵称修改成功,可能存在问题")

# 测试包含特殊字符的昵称
special_nickname = "!@#$%"
nickname_input.clear()
nickname_input.send_keys(special_nickname)
save_button.click()
time.sleep(2)
try:
error_message = driver.find_element(By.ID, "nickname_error")
print("测试用例 2:包含特殊字符的昵称修改失败,提示正常")
except NoSuchElementException:
print("测试用例 2:包含特殊字符的昵称修改成功,可能存在问题")

# 测试用例 3:邮箱地址修改,是否进行格式验证
email_input = driver.find_element(By.ID, "setting_input_email")

# 测试无效邮箱格式
invalid_email = "invalid_email"
email_input.clear()
email_input.send_keys(invalid_email)
save_email_button = driver.find_element(By.ID, "setting_submit_email")
save_email_button.click()
time.sleep(2)
try:
error_message = driver.find_element(By.ID, "email_error")
print("测试用例 3:无效邮箱格式修改失败,提示正常")
except NoSuchElementException:
print("测试用例 3:无效邮箱格式修改成功,可能存在问题")

# 测试有效邮箱格式
valid_email = "valid@example.com"
email_input.clear()
email_input.send_keys(valid_email)
save_email_button.click()
time.sleep(2)
try:
success_message = driver.find_element(By.ID, "email_success")
print("测试用例 3:有效邮箱格式修改成功")
except NoSuchElementException:
print("测试用例 3:有效邮箱格式修改失败,可能存在问题")

time.sleep(5)
# 测试用例 4:电话号码修改,号码位数和格式是否正确
phone_input = driver.find_element(By.ID, "setting_input_phoneNum")

# 测试位数不足的电话号码
short_phone = "1234567"
phone_input.clear()
phone_input.send_keys(short_phone)
save_phone_button = driver.find_element(By.ID, "setting_submit_phoneNum")
save_phone_button.click()
time.sleep(2)
try:
error_message = driver.find_element(By.ID, "phone_error")
print("测试用例 4:位数不足的电话号码修改失败,提示正常")
except NoSuchElementException:
print("测试用例 4:位数不足的电话号码修改成功,可能存在问题")

# 测试位数过多的电话号码
long_phone = "123456789012345"
phone_input.clear()
phone_input.send_keys(long_phone)
save_phone_button.click()
time.sleep(2)
try:
error_message = driver.find_element(By.ID, "phone_error")
print("测试用例 4:位数过多的电话号码修改失败,提示正常")
except NoSuchElementException:
print("测试用例 4:位数过多的电话号码修改成功,可能存在问题")

# 测试格式错误的电话号码(假设电话号码只能是数字)
invalid_format_phone = "abcdefg"
phone_input.clear()
phone_input.send_keys(invalid_format_phone)
save_phone_button.click()
time.sleep(2)
try:
error_message = driver.find_element(By.ID, "phone_error")
print("测试用例 4:格式错误的电话号码修改失败,提示正常")
except NoSuchElementException:
print("测试用例 4:格式错误的电话号码修改成功,可能存在问题")
time.sleep(2)

# 测试用例5: 能否更改密码
# 定位原密码输入框
old_password_input = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "settings_input_oldPassword"))
)

# 定位新密码输入框
new_password_input = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "settings_input_newPassword"))
)

# 定位确认密码输入框
confirm_password_input = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "settings_input_passwordRepeat"))
)

# 定位提交按钮
submit_button = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "settings_submit_password"))
)
# 所有输入框为空,点击提交按钮
submit_button.click()
time.sleep(2)

try:
old_password_error = driver.find_element(By.CSS_SELECTOR, "#settings_input_oldPassword + .invalid-feedback")
new_password_error = driver.find_element(By.CSS_SELECTOR, "#settings_input_newPassword + .invalid-feedback")
confirm_password_error = driver.find_element(By.CSS_SELECTOR, "#settings_input_passwordRepeat + .invalid-feedback")

if old_password_error.is_displayed() and new_password_error.is_displayed() and confirm_password_error.is_displayed():
print("测试用例 5:所有输入框为空,错误提示显示正常")
else:
print("测试用例 5:所有输入框为空,错误提示显示异常")
except NoSuchElementException:
print("测试用例 1:所有输入框为空,未显示错误提示")

# 输入正确的原密码、新密码和确认密码,点击提交按钮
old_password = "123456" # 替换为实际的原密码
new_password = "123" # 替换为实际的新密码
confirm_password = new_password

old_password_input.send_keys(old_password)
new_password_input.send_keys(new_password)
confirm_password_input.send_keys(confirm_password)

submit_button.click()
time.sleep(2)
current_url = driver.current_url
# 这里需要根据实际情况判断密码修改是否成功,例如检查是否有成功提示信息
if current_url == "http://127.0.0.1:9580/sign-in.html":
print("测试用例 5:输入正确信息,密码修改成功,页面跳转正常")
else:
print("测试用例 5:输入正确信息,页面跳转异常")

# 新密码和确认密码不一致,点击提交按钮
# 重新登陆,定位用户名输入框并输入用户名
username_input = driver.find_element(By.ID, "username")
username_input.send_keys(username)

# 定位密码输入框并输入密码
password_input = driver.find_element(By.ID, "password")
password_input.send_keys(new_password)

# 定位登录按钮并点击
login_button = driver.find_element(By.ID, "submit")
login_button.click()

time.sleep(4)

# 点击用户头像,展开下拉菜单
avatar = driver.find_element(By.ID, "index_nav_avatar")
avatar.click()
time.sleep(2)

# 点击个人中心进入修改页面
personal_center = driver.find_element(By.ID, "index_user_settings")
personal_center.click()
time.sleep(2)

old_password_input = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "settings_input_oldPassword"))
)

# 定位新密码输入框
new_password_input = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "settings_input_newPassword"))
)

# 定位确认密码输入框
confirm_password_input = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "settings_input_passwordRepeat"))
)

# 定位提交按钮
submit_button = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "settings_submit_password"))
)
old_password_input.send_keys(new_password)
new_password_input.send_keys("different_password")
confirm_password_input.send_keys("another_different_password")

submit_button.click()
time.sleep(5)

# 这里需要根据实际情况判断是否有相应的错误提示
# 等待提示信息出现
try:
# 等待提示信息可见
WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.CSS_SELECTOR, ".jq-toast-single.jq-has-icon.jq-icon-warning"))
)

# 获取提示信息的文本内容
toast_message = driver.find_element(By.CSS_SELECTOR, '.jq-toast-single.jq-has-icon.jq-icon-warning').text
message_text = toast_message.strip() # 使用strip()去除多余空格

# 检查提示信息是否正确
if "两次输入的密码不相同" in message_text:
print("测试用例通过:两次输入的密码不一致时提示正确")
else:
print(f"测试用例失败:未找到正确的提示信息,实际内容为:'{message_text}'")
except Exception as e:
print(f"测试用例失败:提示信息未在10秒内显示,错误信息:{e}")
except Exception as e:
print(f"测试用例失败:发生意外错误 - {str(e)}")
finally:
# 关闭浏览器
driver.quit()

3.4 性能测试

3.4.1 测试目的

本次性能测试目的是评估论坛项目在不同负载下,登录、注册、发布帖子、回复帖子这四项核心功能的性能表现,包括系统响应时间、吞吐量、并发用户数等指标。

3.4.2 测试环境

  1. 操作系统:Windows 10 家庭中文版 64 位(10.0,内部版本 19045)
  2. 系统制造商:LENOVO
  3. 处理器: AMD Ryzen 5 5600H with Radeon Graphics(12 CPUs),~3.3GHz内存:16384MB RAM
  4. DirectX 版本: DirectX 12

3.4.3 测试场景设计

登录功能测试场景

场景 1:并发登录测试

并发用户数:10、50、100、200、500

持续时间:每个并发级别持续 1 分钟内完成

信息类别 具体信息项 说明
接口相关信息 http://127.0.0.1:9580/user/login 登录请求要访问的完整网络地址
请求方法 POST
请求头信息 content-type:application/x-www-form-urlencoded
请求参数信息 参数名称 username&password
响应相关信息 响应状态码 登录成功和失败对应的HTTP状态码
响应体内容 成功响应码:200
其他信息 是否需要前置操作 不需要
是否有并发或循环要求 以具体测试情况为准

结果分析(示例)
测试在10s内并发200组用户登录

系统在处理登录请求时,响应时间表现良好,大部分请求都能在较短时间内完成,且没有出现请求失败的情况,吞吐量相对较低(考虑是数据量较少的因素)。

注册功能测试场景

场景 1:并发注册测试

并发用户数:10、30、50、80、100

持续时间:每个并发级别持续 2 分钟内完成

信息类别 具体信息项 说明
接口相关信息 http://127.0.0.1:9580/user/register
请求方法 POST
请求头信息 content-type:application/x-www-form-urlencoded
请求参数信息 参数名称 username&password&passwordRepeat&nickname
响应相关信息 响应状态码 登录成功和失败对应的HTTP状态码
响应体内容 成功响应码:200
其他信息 是否需要前置操作 不需要
是否有并发或循环要求 以具体测试情况为准

结果分析(示例)
测试在1分钟内并发100组用户登录


系统在处理注册请求时,响应时间表现良好,大部分请求都能在较短时间内完成,且没有出现请求失败的情况。

发布帖子功能测试场景

场景 1:并发发布帖子测试

并发用户数:10、30、50、80、100

持续时间:每个并发级别持续 1 分钟内

信息类别 具体信息项 说明
接口相关信息 http://127.0.0.1:9580/article/create 发布请求要访问的完整网络地址
请求方法 POST
请求头信息 content-type:application/x-www-form-urlencoded
请求参数信息 参数名称和类型 boardId&title&content
响应相关信息 响应状态码 登录成功和失败对应的HTTP状态码
响应体内容 成功响应码:200
其他信息 是否需要前置操作 需要成功登录并跳转到主页
是否有并发或循环要求 以具体测试情况为准

结果分析(示例)
测试在20s内100个用户并发发布100个帖子


系统在处理登录以及发布帖子请求时,响应时间较长(因为发布帖子数过多),没有出现请求失败的情况。

回复帖子功能测试场景

场景 1:并发回复帖子测试

并发用户数:10、30、50、80、100

持续时间:每个并发级别持续 1 分钟内

信息类别 具体信息项 说明
接口相关信息 http://127.0.0.1:9580/reply/create 回复请求要访问的完整网络地址
请求方法 POST
请求头信息 content-type:application/x-www-form-urlencoded
请求参数信息 参数名称和类型 articleId&content
响应相关信息 响应状态码 登录成功和失败对应的HTTP状态码
响应体内容 成功响应码:200
其他信息 是否需要前置操作 需要成功登录并跳转到主页
是否有并发或循环要求 以具体测试情况为准

结果分析(示例)
测试在10内100个用户并发对帖子进行回复


系统在处理回复帖子请求时,响应时间表现良好,大部分请求都能在较短时间内完成,没有出现请求失败的情况。

3.4.4 脚本编写

登录功能脚本

添加线程组:设置线程数、Ramp - Up 时间、循环次数等参数,根据不同测试场景进行配置。

添加 HTTP 请求:设置请求 URL 为登录接口地址,请求方法为 POST,在请求体中添加用户名和密码参数。

添加断言:添加响应断言,验证返回的状态码为 200,以及响应体中包含登录成功的标识信息。

注册功能脚本

添加线程组:同登录功能脚本设置线程相关参数。

添加 HTTP 请求:请求 URL 为注册接口地址,请求方法为 POST,在请求体中添加用户名、密码、邮箱等注册所需参数。参数值可通过 CSV 数据文件设置,实现数据驱动测试。

添加断言:验证响应状态码为 200,响应体中包含注册成功提示信息。

发布帖子功能脚本

添加线程组:配置线程参数。

添加 HTTP 请求:请求 URL 为发布帖子接口地址,请求方法为 POST。在请求体中添加帖子标题、内容、所属板块等参数,可通过 CSV 文件设置不同的帖子内容。

添加断言:检查响应状态码,以及响应体中是否包含帖子发布成功的提示。

回复帖子功能脚本

添加线程组:设置线程参数。

添加 HTTP 请求:请求 URL 为回复帖子接口地址,请求方法为 POST,请求体中包含帖子 ID、回复内容等参数。

添加断言:断言响应状态码为 200,且响应体中有回复成功的信息。

3.4.5 测试执行

测试环境部署

在服务器上部署论坛项目及相关依赖。

在测试机上安装并配置 JMeter。

测试执行步骤

打开 JMeter,导入编写好的测试脚本。

根据测试场景设计,依次修改线程组中的并发用户数、持续时间等参数。

启动测试,记录每个测试场景下的测试结果,包括响应时间、吞吐量、错误率等指标。

测试过程中,密切关注服务器的 CPU、内存、磁盘 I/O 等资源使用情况。

4. 总结

4.1 测试成果概述

本次测试围绕论坛项目的核心功能与性能展开,覆盖用户管理、版块管理、帖子管理、回复管理四大模块,完成了功能测试、自动化测试及性能测试。测试结果表明,系统核心业务流程(如注册登录、帖子发布与回复)运行基本稳定,能够满足用户的基本交互需求。通过性能测试验证了系统在多组用户操作场景下的可靠性,未出现大规模请求失败或崩溃现象。


4.2 测试发现的主要问题

  1. 功能缺陷

    • 用户注册与信息修改功能未对输入内容进行严格的格式校验(如用户名特殊字符、密码强度、电话号码位数等)。
    • 头像修改功能未完全实现,图片上传后无法正常保存或显示。
    • 帖子内容中直接插入外部图片链接时显示异常,需依赖内置图片上传功能。
  2. 安全性不足

    • 登录与注册接口缺乏防暴力破解机制,如验证码或请求频率限制。
    • 敏感操作(如密码修改)未强制要求二次身份验证。
  3. 性能瓶颈

    • 高并发场景下(如100组用户同时发布帖子),响应时间显著延长,存在数据库写入延迟问题。
    • 持续压力测试中,服务器CPU占用率峰值达90%,内存管理有待优化。
  4. 用户体验问题

    • 错误提示信息不够明确(如“注册失败”未具体说明原因)。
    • 界面交互细节需优化(如密码显示/隐藏按钮点击反馈延迟)。

4.3 改进建议

  1. 功能优化

    • 增加输入字段的格式校验(如用户名长度限制、密码复杂度规则、邮箱与电话格式验证)。
    • 完善头像上传功能,支持主流图片格式(JPG/PNG)并限制文件大小。
    • 优化帖子内容渲染逻辑,兼容外部图片链接的直接显示。
  2. 安全性增强

    • 引入验证码机制或IP限流策略,防止恶意注册与登录尝试。
    • 关键操作(如密码修改)增加短信或邮箱验证环节。
  3. 性能调优

    • 对高频接口(如登录、发帖)引入缓存机制(Redis),减少数据库直接访问压力。
    • 优化SQL查询语句,对帖子列表分页查询添加索引支持。
    • 扩展服务器资源配置或采用负载均衡方案,提升并发处理能力。
  4. 用户体验提升

    • 细化错误提示信息(如“用户名已存在”“密码需包含大小写字母”)。
    • 优化前端交互响应速度,减少页面加载等待时间。

4.4 项目质量评价

当前论坛系统在功能完整性与核心流程稳定性上已达到基本可用标准,但部分细节功能与性能表现仍需完善。


4.5 后续计划

  1. 针对本次测试发现的高优先级问题,制定修复排期并跟踪验证。
  2. 补充兼容性测试(多浏览器、移动端适配)与安全渗透测试。
  3. 定期进行压力测试,监控生产环境性能指标,确保系统长期稳定运行。

测试结论:通过基本验收。