一、报告概述
1、项目背景
商城系统是一款基于 Web 的在线购物平台,主要用于商品展示、商品搜索、用户登录注册、购物车管理、订单提交和订单查询等功能。系统面向普通用户和后台管理员,提供完整的线上购物流程。
系统主要模块包括:
用户管理:注册、登录、退出登录
商品管理:商品分类、商品搜索、商品详情
购物车管理:加入购物车、修改数量、删除商品
订单管理:提交订单、查看订单、取消订单
地址管理:新增地址、修改地址、删除地址
2、测试目的
1. 功能验证
验证用户注册、登录功能是否正常
验证商品浏览、搜索、详情查看是否正常
验证购物车添加、修改、删除功能是否正常
验证订单提交和订单查询流程是否正确
2. 用户体验
检查页面布局是否清晰
检查操作流程是否简单
检查错误提示是否明确
检查按钮和输入框是否易用
3. 系统稳定性
测试页面加载是否正常
测试多次操作后系统是否稳定
测试购物车和订单数据是否正确
测试异常情况下是否有提示
4. 安全性
检查未登录是否能访问订单等页面
检查用户是否只能查看自己的订单
检查输入框是否过滤特殊字符
检查订单金额是否不能随意修改
5. 兼容性
验证 Chrome、Edge 浏览器是否正常
验证 Windows 10、Windows 11 是否正常
验证不同分辨率下页面是否正常显示
3、测试环境
操作系统:Windows 10 / Windows 11
浏览器:Chrome、Edge
测试工具:Selenium、JMeter、Postman
二.测试用例

三.手动测试
1.注册功能
场景1:输入用户名,密码,验证码并点击同意协议注册
预期结果:成功注册来到商城系统首页


场景2:已存在的账号重新注册
预期结果:注册失败,显示账号已注册

场景三:验证码错误
预期结果:显示验证码错误,注册失败

场景四:不勾选协议注册
预期结果:会提示勾选协议,注册失败

2.登录功能
场景1:输入账号密码,验证码
预期结果:成功登录,来到个人中心页面


场景2:输入未注册的账号
预期结果:显示账号不存在,登录失败

场景3:输入错误密码
预期结果:显示密码错误,登录失败

场景4:输入错误验证码
预期结果:显示验证码错误,登录失败

3.商城首页功能
场景1:搜索功能,输入背包点击搜索按钮
预期结果:来到背包页面


场景2:点击数码办公里的手机标签,看能否跳转到对应页面
预期结果:跳转到手机页面


场景3:推荐页功能,点击推荐的商品页
预期结果:跳转到对应的商品页


场景4:购物车功能,
预期结果:成功加入购物车


场景5:点击购买功能,填写地址,提交订单
预期结果:能成功购买



注:到最后一步提交订单界面,但是没有支付方式,毕竟这只是一个web商城界面,主要用来测试,不可能真的付款
4.个人中心功能
场景1:修改头像功能,点击确认上传
预期结果:修改成功


场景2:修改地址功能
预期结果:修改成功



场景3:删除地址功能
预期结果:删除成功


场景4:安全退出功能
预期结果:回到未登录的商城首页


5.我的收藏功能
场景1:点击我的收藏里的商品收藏按钮
预期结果:来到我收藏的订单


6.购物车功能
场景1:收藏购物车里的商品
预期结果:收藏成功

场景2:删除购物车里的商品
预期结果:删除成功


四.兼容性测试
场景1:在Chrome浏览器下登录
预期结果:一切正常


场景2:在Edge浏览器下登录
预期结果:一切正常


五.自动化测试
项目架构:

1.Utils.py
python
import os
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service as ChromeService
from selenium.webdriver.edge.service import Service as EdgeService
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from webdriver_manager.chrome import ChromeDriverManager
from webdriver_manager.microsoft import EdgeChromiumDriverManager
from config import (
BROWSER,
CAPTCHA_SELECTOR,
LOGIN_BUTTON_SELECTOR,
LOGIN_LINK_SELECTOR,
PASSWORD,
PASSWORD_SELECTOR,
USERNAME_SELECTOR,
USERNAME,
WAIT_TIME,
)
class Utils:
"""自动化测试公共方法:打开浏览器、定位元素、点击、输入、截图。"""
def __init__(self):
print("启动浏览器")
if BROWSER.lower() == "edge":
self.driver = webdriver.Edge(service=EdgeService(EdgeChromiumDriverManager().install()))
else:
self.driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install()))
print("浏览器启动成功")
self.driver.maximize_window()
self.driver.set_page_load_timeout(30)
self.wait = WebDriverWait(self.driver, WAIT_TIME)
def open_url(self, url):
print("打开网页:", url)
self.driver.get(url)
def find(self, selector):
return self.wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, selector)))
def click(self, selector):
self.wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, selector))).click()
def input_text(self, selector, text):
element = self.find(selector)
element.clear()
element.send_keys(text)
def get_text(self, selector):
return self.find(selector).text
def switch_to_new_window(self):
new_window = self.driver.window_handles[-1]
self.driver.switch_to.window(new_window)
print("已切换到新标签页:", self.driver.current_url)
def click_and_switch_to_new_window(self, selector):
old_windows = self.driver.window_handles
old_url = self.driver.current_url
self.click(selector)
self.wait.until(
lambda driver: len(driver.window_handles) > len(old_windows)
or driver.current_url != old_url
)
if len(self.driver.window_handles) > len(old_windows):
self.switch_to_new_window()
else:
print("当前页面已跳转:", self.driver.current_url)
def sleep(self, seconds=1):
time.sleep(seconds)
def save_img(self, name):
date_dir = time.strftime("%Y-%m-%d")
img_dir = os.path.join(os.getcwd(), "images", date_dir)
os.makedirs(img_dir, exist_ok=True)
now_time = time.strftime("%H-%M-%S")
img_path = os.path.join(img_dir, name + "_" + now_time + ".png")
self.driver.save_screenshot(img_path)
return img_path
def login(self, username=USERNAME, password=PASSWORD):
print("点击首页登录入口")
self.click(LOGIN_LINK_SELECTOR)
print("输入账号")
self.input_text(USERNAME_SELECTOR, username)
print("输入密码")
self.input_text(PASSWORD_SELECTOR, password)
captcha = input("请输入页面验证码:")
print("输入验证码")
self.input_text(CAPTCHA_SELECTOR, captcha)
print("点击登录按钮")
self.click(LOGIN_BUTTON_SELECTOR)
self.sleep(2)
def quit(self):
self.driver.quit()
2.Mall_CartTest.py
python
import os
import sys
import unittest
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from config import BASE_URL, CART_SELECTOR
from common.Utils import Utils
class CartTest(unittest.TestCase):
def setUp(self):
self.web = Utils()
def tearDown(self):
self.web.quit()
def test_open_cart(self):
self.web.open_url(BASE_URL)
self.web.login()
self.web.click(CART_SELECTOR)
self.web.sleep(1)
self.web.save_img("cart")
self.assertIn("购物车", self.web.driver.page_source)
if __name__ == "__main__":
unittest.main()
3.Mall_GoodsDetailTest.py
python
import os
import sys
import unittest
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from config import (
BASE_URL,
FIRST_GOODS_SELECTOR,
GOODS_DETAIL_MARK_SELECTOR,
SEARCH_BUTTON_SELECTOR,
SEARCH_INPUT_SELECTOR,
SEARCH_KEYWORD,
)
from common.Utils import Utils
class GoodsDetailTest(unittest.TestCase):
def setUp(self):
self.web = Utils()
def tearDown(self):
self.web.quit()
def test_open_goods_detail(self):
self.web.open_url(BASE_URL)
self.web.input_text(SEARCH_INPUT_SELECTOR, SEARCH_KEYWORD)
self.web.click(SEARCH_BUTTON_SELECTOR)
self.web.sleep(1)
self.web.save_img("goods_search_result")
print("搜索后页面:", self.web.driver.current_url)
self.web.click_and_switch_to_new_window(FIRST_GOODS_SELECTOR)
self.web.sleep(1)
self.web.save_img("goods_detail")
self.assertTrue(self.web.find(GOODS_DETAIL_MARK_SELECTOR).is_displayed())
if __name__ == "__main__":
unittest.main()
4.Mall_HomeTest.py
python
import os
import sys
import unittest
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from config import BASE_URL
from common.Utils import Utils
class HomeTest(unittest.TestCase):
def setUp(self):
self.web = Utils()
def tearDown(self):
self.web.quit()
def test_open_home(self):
self.web.open_url(BASE_URL)
self.web.sleep(1)
self.web.save_img("home")
self.assertIn("49.235.61.184", self.web.driver.current_url)
if __name__ == "__main__":
unittest.main()
5.Mall_LoginTest.py
python
import os
import sys
import unittest
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from config import BASE_URL
from common.Utils import Utils
class LoginTest(unittest.TestCase):
def setUp(self):
self.web = Utils()
def tearDown(self):
self.web.quit()
def test_user_login(self):
self.web.open_url(BASE_URL)
self.web.login()
self.web.save_img("user_login")
self.assertTrue("login" not in self.web.driver.current_url.lower())
if __name__ == "__main__":
unittest.main()
6Mall_SearchTest.py
python
import os
import sys
import unittest
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from config import BASE_URL, SEARCH_BUTTON_SELECTOR, SEARCH_INPUT_SELECTOR, SEARCH_KEYWORD
from common.Utils import Utils
class SearchTest(unittest.TestCase):
def setUp(self):
self.web = Utils()
def tearDown(self):
self.web.quit()
def test_search_goods(self):
self.web.open_url(BASE_URL)
self.web.input_text(SEARCH_INPUT_SELECTOR, SEARCH_KEYWORD)
self.web.click(SEARCH_BUTTON_SELECTOR)
self.web.sleep(2)
self.web.save_img("search_goods")
self.assertIn(SEARCH_KEYWORD, self.web.driver.page_source)
if __name__ == "__main__":
unittest.main()
7.config.py
python
BASE_URL = "http://49.235.61.184/"
BROWSER = "edge"
WAIT_TIME = 10
USERNAME = "youya"
PASSWORD = "123456"
SEARCH_KEYWORD = "手机"
# 登录页面
LOGIN_LINK_SELECTOR = "body > div.body-content-container > div.body-content-formal-container > div.header-top > div > ul.top-nav-left.top-nav-left-content.am-hide-sm-only > div > div > a:nth-child(3)"
USERNAME_SELECTOR = "form input[type='text']"
PASSWORD_SELECTOR = "form input[type='password']"
CAPTCHA_SELECTOR = "body > div.body-content-container > div.body-content-formal-container > div.am-g.user-login-container.am-padding-top-0.am-padding-bottom-0.theme-data-edit-event > div > div.am-container > div.am-u-sm-12.am-u-md-6.am-u-lg-4.user-right-container > div.am-radius-lg.am-background-white > div > div.am-tabs-bd.am-border-0 > div.am-tab-panel.am-active > form > div:nth-child(3) > input"
LOGIN_BUTTON_SELECTOR = "form button[type='submit'], form input[type='submit']"
# 搜索和商品
SEARCH_INPUT_SELECTOR = "#search-input"
SEARCH_BUTTON_SELECTOR = "#ai-topsearch"
FIRST_GOODS_SELECTOR = ".item[data-module='goods'] .goods-title a"
GOODS_DETAIL_MARK_SELECTOR = ".system-goods-detail"
# 购物车
CART_SELECTOR = "body > div.body-content-container > div.body-content-formal-container > div.header-top > div > ul.top-nav-right > div.top-nav-items.top-nav-items-cart > div"
8.RunTest.py
python
import unittest
case_path = "./tests"
discover = unittest.defaultTestLoader.discover(case_path, pattern="Mall_*Test.py")
runner = unittest.TextTestRunner(verbosity=2)
runner.run(discover)
第六章 商城系统性能测试
1. 性能测试目标
本章主要使用 Apache JMeter 对商城系统进行性能测试,测试目标是验证系统在一定并发访问下的响应时间、吞吐量、错误率和稳定性。由于本商城系统登录功能包含图形验证码,JMeter 无法稳定自动完成验证码识别,因此本次性能测试暂不包含登录、购物车和订单提交等需要登录态的接口,重点测试游客可直接访问的核心浏览功能。
本次测试主要关注以下几个指标:
响应时间:接口从发送请求到接收响应所消耗的时间。
吞吐量:系统单位时间内能够处理的请求数量。
错误率:请求失败数量占总请求数量的比例。
活跃线程数:测试过程中实际运行的并发用户数量。
通过这些指标,可以初步判断商城系统在并发访问下的性能表现,并发现系统中可能存在的性能瓶颈。
2. 测试接口范围
本次性能测试选择商城系统中无需登录即可访问的核心浏览功能作为测试对象,主要包括首页访问、商品分类、商品列表、商品详情和商品搜索五个场景。
测试接口范围如下:
| 序号 | 测试场景 | 请求方式 | 说明 |
|---|---|---|---|
| 1 | 首页访问 | GET | 测试商城首页基础访问能力 |
| 2 | 商品分类 | GET | 测试商品分类页面加载能力 |
| 3 | 商品列表 | POST | 测试根据分类加载商品列表的能力 |
| 4 | 商品详情 | GET | 测试商品详情页面访问能力 |
| 5 | 商品搜索 | GET | 测试关键词搜索结果页面访问能力 |
本次没有测试支付接口,因为当前商城系统暂不支持支付功能;也没有测试购物车和订单接口,因为这些接口需要登录状态,而登录功能存在图形验证码校验,容易影响性能测试脚本的稳定执行。
3.JMeter 脚本设计
本次测试使用 JMeter 创建测试计划,并在线程组中添加对应的 HTTP 请求。脚本结构主要包括线程组、HTTP 信息头管理器、五个业务请求、聚合报告以及可视化监听器。
JMeter 脚本结构如下:
测试计划
└── 线程组
├── HTTP信息头管理器
├── 01_首页访问
├── 02_商品分类事务
│ └── 商品分类请求
├── 03_商品列表事务
│ └── 商品列表请求
├── 04_商品详情事务
│ └── 商品详情请求
├── 05_商品搜索事务
│ └── 商品搜索请求
├── 聚合报告
├── TPS可视化
├── 响应时间可视化
└── 活跃线程数可视化
其中,商品列表接口为 POST 请求,需要携带分类 ID、页码和每页数量等参数。其他接口主要为 GET 请求,用于访问对应的页面资源。
【图6-1JMeter测试计划结构图】

4. 测试场景设置
在正式压测前,先使用 1 个线程、1 次循环对五个接口进行单次验证,确认每个接口都可以正常返回。单次验证通过后,再逐步增加并发数进行测试。
本次测试主要设置了以下几组场景:
| 测试场景 | 线程数 | Ramp-Up 时间 | 循环次数 | 说明 |
|---|---|---|---|---|
| 单次验证 | 1 | 1秒 | 1 | 验证脚本是否能正常执行 |
| 低并发测试 | 5 | 5秒 | 1 / 2 | 验证系统在低并发下的稳定性 |
| 中等并发测试 | 10 | 10秒 | 1 | 观察系统在并发提升后的表现 |
在测试过程中发现,当并发提升到 10 时,首页访问接口开始出现偶发异常,并且响应时间明显升高。因此本次测试没有继续提升到 50 并发,而是将 10 并发作为本次测试中的主要观察点。
5. 聚合报告结果分析
在单线程验证阶段,首页访问、商品分类、商品列表、商品详情和商品搜索五个场景均能正常返回,异常率为 0%,说明 JMeter 脚本配置正确。
在 5 并发测试中,系统整体运行稳定,未出现异常请求,说明商城系统在低并发场景下可以正常处理游客浏览类请求。
在 10 并发、1 次循环测试中,总样本数为 50,整体异常率为 2.00%。其中首页访问接口异常率为 10.00%,其余商品分类、商品列表、商品详情和商品搜索接口异常率均为 0.00%。这说明系统在 10 并发下大部分接口能够正常响应,但首页访问存在一定的不稳定情况。
从响应时间来看,10 并发测试中系统整体平均响应时间较高,TOTAL 平均响应时间约为 10858ms,95% 响应时间达到 41287ms,最大响应时间达到 70214ms。首页访问接口的平均响应时间和最大响应时间都明显偏高,是本次测试中较明显的性能瓶颈。
【图6-2:单线程验证聚合报告】

【图6-3:5并发聚合报告】

【图6-4:10并发聚合报告】

6. TPS 可视化分析
TPS 表示系统每秒能够处理的事务数量。从 TPS 可视化图可以看到,本次测试中各接口整体吞吐量不高,大多数时间维持在 1 transactions/sec 左右,商品列表接口在部分时间点达到 2 transactions/sec。
结合聚合报告结果来看,商城系统在低并发情况下可以完成请求处理,但整体吞吐能力有限。当并发提升后,首页访问接口出现失败记录,说明首页访问在并发场景下存在一定压力。
【图6-5:TPS可视化结果】

7. 响应时间可视化分析
从响应时间变化趋势图可以看到,各接口响应时间存在明显差异。其中商品列表接口响应最快,整体较为稳定,大部分时间保持在较低水平;首页访问接口响应时间波动最大,部分时间点响应时间明显升高,最高接近 63 秒。
商品分类、商品详情和商品搜索接口也存在一定波动,但整体低于首页访问接口。由此可以看出,首页访问是本次测试中最容易出现性能问题的场景。首页通常包含较多页面资源、样式文件、图片资源和页面渲染内容,因此在并发访问时更容易出现响应时间升高的问题。
【图6-6:响应时间可视化结果】

8. 活跃线程数可视化分析
活跃线程数图用于观察测试过程中 JMeter 是否按照预设线程数正常启动和释放线程。从图中可以看到,测试开始后线程数逐步上升到设定的 5 个并发线程,随后随着请求执行完成,线程数逐步下降到 0。
这说明本次测试过程中线程启动和释放过程正常,JMeter 能够按照设置的 Ramp-Up 时间完成并发模拟,测试执行过程整体正常。
【图6-7:活跃线程数可视化结果】

9.性能测试报告






10. 测试结论与优化建议
通过本次 JMeter 性能测试可以看出,商城系统在低并发场景下能够正常处理首页访问、商品分类、商品列表、商品详情和商品搜索等核心浏览功能。其中商品列表接口响应最快,稳定性较好;首页访问接口响应时间波动较大,并且在 10 并发测试中出现少量异常,说明首页访问是当前系统中较明显的性能瓶颈。
针对测试结果,可以从以下几个方面进行优化:
-
优化首页资源加载,减少首页中不必要的 CSS、JS 和图片资源。
-
对首页、商品分类等高频访问页面增加缓存,降低服务器重复处理压力。
-
压缩静态资源,减少页面加载体积,提高页面响应速度。
-
检查服务器配置、带宽和 Web 服务参数,避免并发访问时出现请求阻塞。
-
后续可以在优化后重新进行 10 并发及更高并发测试,对比优化前后的性能变化。
整体来看,本次性能测试完成了从接口选择、脚本设计、并发测试到结果分析的完整流程,能够较好地反映商城系统在游客浏览场景下的性能表现。
第八章 bug描述
1.该项目不支持支付功能.
2.性能测试中所有需要登录的功能都无法测试,因为验证码每次都要手动输入,自动化测试则在pycharm终端手动输入验证码