ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Web项目测试实战:基于在线商城的全流程自动化测试指南

Web项目测试实战:基于在线商城的全流程自动化测试指南

简介:软件测试实战项目(网站项目)是一套面向软件测试初学者与在校学生的完整练习资源,以电子商务网站为被测对象,覆盖前端页面与后端程序代码,帮助读者将功能测试、系统测试、性能测试和静态分析串成完整链路。资源包共一百四十六个文件,压缩后约二十二兆字节,主体为后端代码文件、网页页面与脚本文件,同时包含系统测试报告、性能测试计划、覆盖度报告、数据脚本、演示视频与演示文稿课件,便于边看边练。文档部分整理了静态分析报告、系统测试报告、性能测试报告与覆盖度报告,并给出订单提交等典型电商模块的页面,可对照进行用例设计、缺陷记录和结果分析。已有六千零八十九人浏览学习,适合希望积累网站测试实战经验、快速上手测试文档撰写的读者。

1. Web 项目软件测试实战:为什么拿一套在线商城练手最划算

不少准备入行软件测试的人,把概念背得滚瓜烂熟,一到面试环节,面试官问“你独立测试过完整的 Web 项目吗”,立刻就露怯。而另一边,已经在做功能测试的工程师,想转自动化,看了一堆 Selenium、pytest 教程,却发现没地方练手,代码抄下来连个能跑的测试对象都没有。这个问题最直接的解法,就是自己搭一套 Web 项目来当被测系统。常见的做法是拉一个开源商城或后台管理系统,把环境跑起来,从写用例到执行、报缺陷、做回归,完整地走一遍。这篇文章就围绕这条路径,讲清楚测试计划、用例设计、接口测试、UI 自动化怎么做,以及那些不撞一次墙根本不知道的坑。

2. 被测 Web 项目怎么选:在线商城 vs 后台管理系统

2.1 选型标准:不要图大,要图“状态多、权限清、流程长”

很多初学者选被测项目时有个误区:觉得项目越复杂越好,于是去装一套几百个页面的开源 ERP。结果光部署就花了三天,最后连登录页都没测完。选被测项目不是选生产系统,你的目的是在有限时间内覆盖更多测试类型,所以核心标准就三条。

第一,状态要多。以在线商城为例,一个订单有“待付款、已付款、已发货、已签收、已取消、退款中”这么多种状态,每种状态能做什么操作、不能做什么操作,本身就是一批现成的测试点。第二,权限要清。Web 项目最常见的缺陷就藏在角色权限里:普通用户能不能访问管理后台、店长能不能修改商品上下架状态、运营能不能看到不属于自己门店的订单。第三,流程要长。注册、登录、选品、下单、支付、发货、收货,环环相扣,只要中间断一环,就是一条高价值的缺陷记录。

后台管理系统在权限上更有优势,但它的业务逻辑相对单一,用户交互少,做 UI 自动化时能写的用例有限。在线商城则兼顾了功能测试和自动化测试的需求,所以我一般建议优先选商城类项目。如果你手里正好有一个前后端分离的 Spring Boot Web 项目,那更好,因为接口测试可以直接对着后端的 RESTful API 做,返回 JSON 结构清晰,断言写起来顺手。要是只有传统的前后端不分离项目,页面跳转多,UI 自动化比重就得加大,工作量会明显上浮。

2.2 最小可测环境:前端、后端、数据库三件套怎么落地

被测系统跑不起来,后面的测试全是空话。一个最小可测的 Web 环境,至少包含前端服务、后端服务和数据库。以常见的开源商城为例,前端是一个 Vue 或 React 工程,后端是 Spring Boot 工程,数据库用 MySQL。部署顺序上,先把数据库初始化好,再起后端,最后起前端。

# 1. 初始化数据库:执行项目里自带的 SQL 脚本 mysql -uroot -p123456 < shop.sql # 2. 启动后端服务(Spring Boot 项目,需先确认 application.yml 里的数据库连接) cd shop-server mvn spring-boot:run -Dspring-boot.run.profiles=dev # 3. 启动前端开发服务器 cd shop-admin-web npm install npm run dev

这段命令的逻辑是先用项目自带的 shop.sql 把表结构和初始数据建好,后端 Spring Boot 工程通过配置文件里的数据源连接这个库,前端再通过代理转发请求到后端端口。参数上要注意三个地方。application.yml 里的 spring.datasource.url 必须和本地 MySQL 的端口、库名一致,常见错误是默认配置连的是 3306 而本地 MySQL 改过端口。npm install 如果卡在某个依赖上,先检查 Node 版本,Vue 2 的旧项目在 Node 18 以上经常编译失败。启动顺序不能乱,先起前端没报错不代表后端可用,因为页面能打开,但登录接口大概率是 502。

这里有个省事的思路:如果不想折腾前端构建,很多开源商城把静态资源打包好后可以直接用 Nginx 托管,后端单独跑。这样环境少一层,排错成本低很多。等以后要学接口测试了,再把它换成前后端分离的完整版。

2.3 用一套开源商城系统快速跑通冒烟测试

环境起来以后,第一件事不是急着写详细用例,而是先跑一遍冒烟测试,确认核心链路是通的。这个习惯直接影响后面所有测试的有效性,我见过不少人在一个根本没部署成功的系统上写了 40 条用例,执行完发现一半是环境问题,白忙一场。

冒烟测试的用例控制在 10 条以内,覆盖:注册新用户、登录、浏览商品列表、查看商品详情、加入购物车、提交订单、支付(Mock 或测试支付通道)、在管理后台新增商品、上下架商品、查看订单列表。执行方式就是纯手工,按正常用户的路径点一遍。这轮不用考虑边界值,也不用管异常场景,核心目标是确认主流程没断。

跑通之后,把冒烟测试的结果截图、请求日志保存下来,这就是你整个实战项目的第一份交付物。后续每轮回归都要先跑冒烟,只有冒烟通过,才允许继续测其他模块。这个“冒烟不过不往下测”的原则,是软件测试流程里最容易被新手忽略、却在真实项目里救命的一条约束。

3. Web 项目的测试计划与需求分析:把“不知道测什么”变成测试点

3.1 需求拆解的方法:从用户故事到功能点和优先级

拿到一个 Web 项目,最怕的不是没有需求文档,而是有文档却不知道从哪看起。我一般按“角色、动作、数据、状态”四个维度拆。

以商城为例,第一步列角色:游客、注册用户、管理员、运营人员。第二步列动作:每个角色能做什么,游客只能浏览,注册用户能下单,管理员能改商品。第三步列数据:每个动作涉及哪些字段,下单要传商品 ID、数量、收货地址,这些字段哪些必填、哪些有格式要求。第四步列状态:数据在不同节点怎么流转,订单从待付款变成已付款之后,用户的取消按钮应该消失。

实操时,我习惯用表格把拆解结果记下来,而不是直接写用例。先把流程图画清楚,再开始写用例。很多人上来就写用例,写到一半发现漏了“支付成功后库存扣减”这个环节,再回头补需求文档,来来回回效率极低。

优先级怎么定?看两个东西:影响范围和出现频率。影响范围大且频率高的,比如登录、下单、支付,定 P0。影响范围小但偶尔出现的,比如优惠券过期提醒,定 P1。只在特定条件下出现的,比如管理员重置密码后用户首次登录强制改密,定 P2。后面做自动化时,P0 用例就是冒烟测试集和每日回归集的来源。

3.2 测试计划里必须写清楚的 5 个字段

测试计划是很多人在实战项目里完全跳过的一步,但这恰恰是面试时最能体现专业度的地方。一份好的测试计划不需要写成几十页的大文档,但下面 5 个字段必须写清楚。

测试范围:明确进本轮测试的功能模块和不测的内容。比如“本次测试覆盖前台商城全部用户流程,不覆盖支付网关的真实扣款逻辑,使用平台提供的沙箱环境”。这一条写清楚,后面出问题了才知道是去找开发还是换测试方案。

测试环境:被测系统地址、数据库版本、浏览器版本、测试数据准备方式。这里特别提醒,不要写“本地环境”四个字就完事,要写具体到“Chrome 131.0,Windows 11,MySQL 8.0,测试账号 user01/user01(密码为 8 位数字字母组合)”。环境写不清楚,缺陷无法复现时,开发第一句话就是问“你什么环境测的”。

测试数据:这是最容易翻车的一块。要提前准备哪些账号、哪些商品、哪些订单状态的数据,谁去准备、什么时间准备好。我通常会建一张数据准备清单,把账号角色和对应权限列出来。

测试进度:每个模块的开始和结束时间,预留出至少 20% 的时间做回归和修缺陷后的验证。时间不留余量,最后大概率会在回归环节压缩用例。

风险与依赖:比如“支付沙箱环境不稳定,可能导致支付用例阻塞,预案是用 Mock 接口绕过”。这一条写出来,是真正做过项目的人和只会背书的人的分水岭。

3.3 测试用例设计:等价类、边界值、场景法的落地模板

用例设计方法在面试八股文里是热门,但落到纸上怎么写才是关键。以注册页的密码输入框为例,一次演示等价类和边界值怎么结合。

| 用例编号 | 输入数据 | 预期结果 | 优先级 | |---------|---------|---------|-------| | REG_001 | 密码为空 | 提示“请输入密码” | P1 | | REG_002 | 密码为 6 位:abc123 | 注册成功 | P0 | | REG_003 | 密码为 5 位:abc12 | 提示“密码长度 6-20 位” | P1 | | REG_004 | 密码为 20 位:a1b2c3d4e5f6g7h8j9k0 | 注册成功 | P1 | | REG_005 | 密码为 21 位:...(21位)| 提示“密码长度 6-20 位” | P1 | | REG_006 | 密码为中文:密码密码密码密码 | 提示“密码仅支持字母和数字” | P2 |

这个模板的逻辑是:先用等价类把输入域分成有效和无效两组,有效数据取 6 位和 20 位两个典型值,无效数据取空、超长、非法字符。再用边界值把长度边界 6 和 20 的相邻值 5 和 21 补上。一个输入框就这么测,整个注册页十几个输入框,用例量立刻上来了。但要注意,用例不是越多越好,而是每个用例都有独立的预期结果,能对应到具体缺陷。

场景法用来补流程性的用例。典型的“用户从浏览到支付成功”全流程是一条用例,而不是把浏览、加购、下单拆成三条独立的用例,因为流程型缺陷只有连贯操作才能暴露。比如支付成功后返回商户页面,页面上显示的订单状态没有刷新,这种问题单点测试是测不出来的。用例写完后做一次同行评审,请身边的人按你的用例走一遍,看看步骤描述是否歧义、预期结果是否可验证。这一步能发现大量“自己能跑但别人看不懂”的用例。

4. 把用例变成结果:接口测试、UI 自动化与回归策略

4.1 接口测试:先用 Postman 手测,再用 Python 脚本化

功能测试做到一定量,就该往接口层走了。接口测试的价值在于:它比 UI 测试稳定,比代码评审更贴近真实使用场景。以商城的登录接口为例,先在 Postman 里手动调通,确认请求方法和参数格式。

常见的登录接口是 POST 请求,路径类似 /api/auth/login,请求体是 JSON 格式。用 Postman 调试时,一旦返回 200,把响应里的 token 复制出来,作为后续所有需要鉴权接口的请求头。这个过程走一遍后,再用 Python 把它脚本化。

import requests # 测试数据:从测试计划的数据清单里取 login_url = "http://127.0.0.1:8080/api/auth/login" login_data = {"username": "user01", "password": "abc123456"} headers = {"Content-Type": "application/json"} # 第一步:登录获取 token response = requests.post(login_url, json=login_data, headers=headers) assert response.status_code == 200, f"登录失败: {response.text}" token = response.json()["data"]["token"] # 第二步:带 token 查询订单列表,验证鉴权链路 order_url = "http://127.0.0.1:8080/api/orders" auth_headers = {"Authorization": f"Bearer {token}"} order_response = requests.get(order_url, headers=auth_headers) assert order_response.status_code == 200 orders = order_response.json()["data"] assert len(orders) >= 1, "该账号下应有至少一条测试订单"

这段脚本的逻辑是先用 requests 库模拟浏览器发起登录请求,拿到 token 后再去请求订单列表接口。这里有两个关键点。第一,断言不能只写状态码,还要校验关键业务数据,比如订单列表长度大于 0,否则接口返回 200 但返回空数组,测试依然通过,没有意义。第二,token 的传递方式要看清项目的实际约定,有些项目用 Authorization 头,有些项目要求放到请求体里,甚至有的项目把 token 放在响应头而不是响应体里,拿到后要确认字段名,不然下一步全是 401。

接口用例的粒度,我建议按“一个业务动作一条用例”来写,新增商品接口一条、修改库存一条、删除商品一条。参数化测试可以往后放,先把单接口的断言做扎实。Python 脚本跑通后,再用 pytest 把这些函数包装成测试用例,加 @pytest.mark.parametrize 做多组数据驱动,这是从手测走向自动化最平滑的一条路。

4.2 UI 自动化:Selenium 打开登录页的最小用例与选择器坑

UI 自动化适合跑主流程回归,不适合用来找新缺陷。这个定位先想清楚,否则你会陷入“写了个自动化脚本,每次跑都挂,修脚本比手动测试还慢”的怪圈。最小可用的 UI 自动化用例,从登录开始。

from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC driver = webdriver.Chrome() try: driver.get("http://127.0.0.1:8080/#/login") # 用显式等待代替固定 sleep,避免网络波动导致元素未加载 username_input = WebDriverWait(driver, 10).until( EC.visibility_of_element_located((By.NAME, "username")) ) password_input = driver.find_element(By.NAME, "password") login_button = driver.find_element(By.CSS_SELECTOR, "button[type='submit']") username_input.send_keys("user01") password_input.send_keys("abc123456") login_button.click() # 断言登录成功:等待页面上出现用户昵称 WebDriverWait(driver, 10).until( EC.text_to_be_present_in_element((By.CLASS_NAME, "user-info"), "user01") ) print("登录成功,UI 自动化用例通过") finally: driver.quit()

这段代码里最重要的是显式等待。很多新手会写成 time.sleep(3),这在本地跑没问题,一旦网络慢或页面加载到 4 秒,用例就挂了。显式等待是轮询元素状态,最多等 10 秒,元素出现了就立刻继续,稳定性高很多。选择器方面,优先用 id 或 name,其次用 CSS 选择器,最后才用 XPath。XPath 不是不能用,而是写得太绝对,比如 //div[3]/div[2]/input,页面稍微改个结构就失效。这一行代码里的按钮选择器用了 button[type='submit'],就是故意避开 class 里那些动态生成的随机类名。

UI 自动化的维护成本高,这是行业的共识,不是你的问题。应对办法是给脚本留好定位信息:元素定位不到时,把当前页面截图保存下来,把 HTML 源码 dump 到文件里。这样脚本挂了你还能知道是元素没加载出来还是选择器写错了,而不是看着一条报错信息干瞪眼。

4.3 回归策略:优先级分层与冒烟测试集

回归测试是 Web 项目里最不能省的一环。每次开发修完缺陷,都要跑一遍回归,确认修复没有引入新问题。我的习惯是分三层做。

第一层是冒烟回归,放 P0 用例,大概 20 到 30 条,覆盖登录、首页加载、添加购物车、提交订单、支付回调、管理后台商品上下架。本来要手动跑,有了上一节写的 UI 自动化脚本后,这一层最先脚本化。第二层是功能回归,放 P1 用例,按模块分组执行,比如订单模块回归时,把所有订单状态的流转用例都跑一遍。第三层是数据专项回归,重点看数据库里的余额、库存、订单金额是否和页面展示一致。这层最容易被忽略,但电商类 Web 项目一旦账实不符,就是线上事故。

回归策略里还要留一个“后悔药”的机制。每次回归前,把测试环境里的数据库做一次备份,用 mysqldump 导出。有些缺陷会把数据改得乱七八糟,比如把测试商品的库存改成负的,没有备份就只能手工改回去。备份命令很简单:

mysqldump -uroot -p123456 shop > shop_backup_$(date +%Y%m%d).sql

这条命令按日期生成备份文件,回归前跑一次,出问题时恢复备份,比手动去改几十条脏数据快得多。我见过不止一个测试环境被玩坏后只能重建整个环境的案例,一个备份命令就能避免这种翻车,没有理由不做。

5. Web 项目测试避坑清单:现象、原因、解决

5.1 用例执行时登录态频繁失效

现象:手动测试时每点几步就要重新登录一次,自动化脚本跑着跑着也 401 了。原因:测试环境的前端每次刷新页面都会重新请求 token,而 token 过期时间很短,或者做了连续请求次数限制。另一个隐蔽原因是浏览器开了多个标签页,后打开的那个页面占用了新的 session,把之前的顶掉了。解决:在测试计划里注明“测试环境 token 有效期配置为 2 小时”,和开发沟通统一改掉;自动化脚本里加一个 token 有效性检查,失效自动跳登录后重新获取,再重试请求。

5.2 用例数量很多但覆盖率很低

现象:用例写了 300 条,执行完发现登录、注册、商品列表占了 220 条,支付、退款、库存只占 30 条。原因:人本能会挑熟悉的、好测的模块多写用例,业务复杂、数据准备麻烦的模块被有意无意地绕过。解决:写用例前先按模块统计测试点分布,每个模块定一个最低用例数;写完用例做一次评审,专门看“哪些模块用例明显偏少”。我自己的要求是,核心交易链路用例数不能低于总数的 30%。

5.3 UI 自动化脚本今天能跑明天就挂

现象:同一段代码,昨天跑通过,今天什么都没改,却报元素找不到。原因:测试环境里商品数据变了,比如首页推荐商品被切换了,导致原本依赖这个元素定位的用例失效。更常见的是前端发版后按钮的 class 或 id 变了。解决:UI 自动化的定位策略不要用绝对路径,优先用带业务语义的属性;收集失败截图,区分是环境数据问题还是代码改动问题;把 UI 自动化限定在冒烟回归层,接口测试才是大规模回归的主角。用接口自动化当回归主力、UI 自动化当冒烟补充,这个分工能让你的脚本稳定度提升一个量级。

5.4 测试环境被玩坏后无法恢复

现象:测完一笔异常支付流程,再去测正常下单,发现订单状态全乱了,或者某件测试商品库存变成负数,第二天所有人都在报障。原因:测试数据没有隔离,异常流程产生的脏数据污染了共享环境。解决:每个测试人员在测试计划里认领自己的数据范围,用前缀区分,比如 user01 的订单只操作 user01 的账号;关键业务表的状态流转,每一步都截图留证;环境坏了优先用备份恢复,不要手动一条条改数据。5.3 里说的备份命令在这里就是救命稻草。

5.5 缺陷复现不了,开发不认

现象:提了一个 Bug“商品详情页偶尔显示价格异常”,开发按描述怎么都复现不出来,直接关闭了你的缺陷单。原因:缺陷描述里缺了前置条件和操作路径,只写了“偶现”。偶现是测试报告里最无效的两个字,等于没写。解决:缺陷描述按“前置条件、操作步骤、实际结果、预期结果、环境信息、截图或录屏”六要素来写。偶现问题时,把网络请求的响应报文复制出来,标明是接口返回的数据不对还是页面渲染不对。这个信息到位了,开发上手定位的效率会高很多,你的缺陷关闭率也会好看。

6. 让这个实战项目成为面试谈资:数据说话与可复现演示

实战项目做得再扎实,讲不出去等于白做。很多人在简历上写“负责商城的软件测试”,面试官问“你测过的项目有哪些模块”“发现了什么印象深刻的缺陷”,回答全靠记流水账。这不行,要把项目过程整理成一套可以展示的成果。

第一,准备一个数字清单。项目一共写了多少个测试用例、覆盖了多少个模块、发现了多少个缺陷、缺陷按严重程度怎么分布、最终回归通过率是多少。这些数字不需要大,但必须真实可查。面试官问“你项目里最大的挑战是什么”,你就拿“下单流程的并发库存问题”举例,说清楚怎么设计并发场景、怎么用脚本去压、最后怎么验证修复结果。数字加场景,比背一百条测试理论都有说服力。

第二,把关键产出物整理成文档。测试计划一份、测试用例一份、缺陷记录一份、测试报告一份。这四份东西就是你在软件测试项目实战里留下的完整证据链。面试时不用把所有内容都讲,挑一份测试报告里最有价值的 3 个缺陷,展开讲分析过程。缺陷的价值不在于难度有多高,而在于你能不能说清“它为什么会导致用户损失、你当时是怎么一步步定位到根因的”。

第三,把自动化项目放进简历的作品栏。接口测试脚本和 UI 自动化脚本整理到一个公开仓库里,README 写清楚环境怎么搭、用例怎么跑、结果怎么查看。面试官要看代码,直接打开仓库就能复现。这里的重点是脚本里的注释和命名规范。变量名写清楚了,比炫技更重要。我自己面试候选人时,就遇到过代码能跑但注释全是拼音缩写、断言逻辑绕了几道弯的,这种项目做得再深也不敢放进来。

最后说一句血泪经验:软件测试这行的门坎不在理论而在手熟,八股文背得再熟,不如把一套 Web 项目从计划到回归完整走一遍。你踩过的每一个坑、补过的每一条用例、修过的每一个自动化脚本,都会在关键时刻帮你顶住面试官和项目的双重压力。希望这篇笔记能帮你在自己的实战项目上少走几段弯路。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进