蓝桥杯软件测试模拟赛1期六模块全流程备考指南 1. 先摸清楚模拟赛1期到底在考什么蓝桥杯软件测试这个赛道跟纯算法赛道完全是两套玩法。算法赛是给你一道题写代码跑用例过了就是过了软件测试赛更像真实项目交付——给你一个被测系统、一份需求说明然后要求你在有限时间里把测试用例、自动化脚本、接口集合、性能脚本、单元测试代码和一份报告全部产出来。第十五届模拟赛1期的题目我拿到手第一反应是这不是在考“你会不会用工具”而是在考“你能不能在时间压力下把一个测试流程跑完整”。这两个能力差得远。先把结论摆出来模拟赛1期的题目结构基本沿着功能测试、自动化测试、接口测试、性能测试、单元测试白盒 测试文档这条主轴铺开分值大致按 20/25/20/20/15 的比例切分不同场次会有浮动这是基于多届真题结构的合理推断具体以当场试卷为准。这个结构其实非常“工程化”——它默认你已经会点 Python、会点 Selenium、会看 JMeter 的聚合报告然后用一个完整的业务场景把这些工具串起来。所以你在准备的时候重点不该是“再学一个工具”而是“把一条从需求到缺陷单的链路练到闭着眼睛也能走完”。1.1 赛题结构的拆解逻辑我一般把这类赛题拆成三层来看。最上层是业务层被测系统通常是一个裁剪过的 Web 后台比如一个商品管理、订单处理或者人员信息维护的模块功能点不会太多十几个页面顶天但每个功能点都会埋一些“看起来正常、实际有坑”的地方。中间层是工具层Selenium/Playwright 做 UI 自动化requests 或 Postman 做接口JMeter 做压测JUnit 或 pytest 做单元测试。最底层是表达层用例怎么写、缺陷单怎么描述、报告怎么组织——这一层最容易被忽略但恰恰是拉开分数的地方。为什么这么拆因为评分是分模块独立打分的工具用错顶多丢一个模块的分但表达层拉胯会同时污染好几个模块的得分。我见过有人自动化脚本跑得飞快结果缺陷单里“复现步骤”只写了“点击按钮报错”评委根本没法复现分就没了。所以我的建议是工具熟练度练到“能用”就够把剩下的精力砸在用例设计和缺陷描述上性价比高得多。再说一个容易被忽略的点模拟赛的题目里需求描述往往是不完整的。真实项目里需求文档也是不完整的这是刻意还原。比如需求里写了“用户名长度 6-20 位”但没写“是否允许中文”“是否区分大小写”“首尾空格怎么处理”。这些空白不是出题人疏忽而是考点——它考你能不能用等价类和边界值把这些隐含规则挖出来写成可执行的用例。你在赛场上遇到这种模糊描述别急着抱怨先把能确定的写死把不确定的列成“待确认项”这个动作本身就是加分项。1.2 各模块能力要求的映射关系我整理了一张表把每个模块考什么、需要什么前置能力、最容易丢分的地方列出来你可以对着自查模块核心考点前置能力高频失分点功能测试用例设计方法组合、缺陷描述质量需求分析、等价类/边界值/判定表用例覆盖不全、只测正向不测反向自动化测试元素定位稳定性、等待策略、断言Python 基础、Selenium/Playwright硬编码 sleep、定位器脆弱、只跑不断言接口测试请求构造、状态码与业务码校验、依赖传递HTTP 协议、JSON 结构、抓包只断言 200、忽略字段级校验、token 未关联性能测试场景建模、线程数计算、报告解读JMeter 元件、并发概念线程数拍脑袋、断言缺失、报告只贴图不分析单元测试覆盖率目标、参数化、MockJUnit/pytest、分支逻辑只写语句覆盖、断言太弱测试文档结构完整性、术语准确测试计划/报告规范章节缺失、结论无数据支撑看懂这张表你就明白这个赛项真正的门槛不在工具而在方法论。等价类、边界值、判定表这些词你可能在课本上背过但真给你一个“会员折扣计算”的需求让你 20 分钟内产出 30 条有效用例很多人就卡住了。我在下面第 2 节会用具体例子把这条路走一遍。1.3 开赛前必须做完的环境自检这个环节看着无聊但每年都有人栽在这上面。模拟赛一般允许自带电脑或者用赛场机器不管你用哪种开赛前 15 分钟必须把这几件事做完做成一个清单贴在脑子里Python 版本与包确认python --version是 3.8 以上pip list里selenium、requests、pytest、pytest-html、openpyxl、PyYAML都在。离线环境要提前把 whl 包下载好放本地目录pip install --no-index --find-links./pkgs -r requirements.txt这条命令要提前试通。浏览器与驱动Chrome 版本和 chromedriver 版本必须对齐大版本号一致就行。我踩过的坑是驱动在 PATH 里但版本不匹配报SessionNotCreatedException排查半天。稳妥做法是在脚本里显式指定Service(executable_path...)别依赖环境变量。JMeter确认bin目录下有jmeter.bat/jmeter.sh启动后语言切换成中文Options → Choose Language → ChineseJVM 内存参数调一下默认 512m 跑几百线程容易 OOM改成HEAP-Xms1g -Xmx2g。数据库客户端很多验证点需要直接查库确认数据落库是否正确DBeaver 或者命令行 mysql 客户端提前连好被测库把连接信息存下来。截图工具与目录建一个固定的evidence/目录脚本里失败截图自动存进去报告里直接引用相对路径。提示环境自检不要等到开赛才做。模拟赛通常提前开放环境你可以在赛前用一套“冒烟脚本”跑一遍——打开首页、登录、点三个菜单、截图保存能跑通说明环境没问题。这套脚本五分钟能写完能帮你省掉开赛后半小时的慌乱。2. 功能测试题用例设计和缺陷单才是基本盘功能测试模块在所有模块里分值占比不是最高但它是最“确定性”的一块——只要你方法用对、覆盖到位分基本能拿满。反过来说这块丢分最冤枉因为它不依赖任何工具熟练度只依赖你对需求的理解深度和表达的规范度。我带过的人里工具玩得飞起但用例写得稀碎的不少最后总分被这块拖后腿。模拟赛1期这类题目的典型形式是给你一段 800-1500 字的需求描述可能配一两张原型图要求你在 40-60 分钟内产出一份测试用例表通常给 Excel 模板字段包括用例编号、模块、标题、前置条件、步骤、预期结果、优先级外加一份缺陷报告。需求里一定有可挖的规则比如金额精度、状态流转、权限边界、并发冲突。2.1 需求分析的切入顺序先画流程再拆点我的习惯是拿到需求先不急着写用例花 5 分钟做三件事画主流程图、标状态节点、圈模糊词。画流程图是为了找场景法的主干和分支。比如“用户提交订单”这个需求主干是“选商品→确认订单→支付→订单完成”分支至少有库存不足、优惠券不可用、支付超时、重复提交、金额为 0、地址为空。这些分支不是靠灵感想出来的是流程图上一个节点一个节点问出来的“这个节点如果失败会怎样如果中途退出会怎样如果两个人同时操作会怎样”标状态节点是为了判定表。凡是出现“状态”的需求几乎必然要用判定表。比如订单状态有“待支付、已支付、已发货、已完成、已取消”每个状态下允许的操作不同能否取消、能否退款、能否评价这就是一张二维表横着是状态竖着是操作交叉点写允许/不允许。这张表一画出来用例数量基本就确定了不会漏。圈模糊词是为了找隐含用例。需求里出现“合理”“适当”“及时”“正常”这类词全是模糊地带必须拆成可验证的条件。“用户名长度合理”就要追问下限是多少、上限是多少、边界值取不取、超长怎么提示、空值怎么处理、纯空格算不算合法。“及时刷新”就要问刷新周期是多少秒、手动刷新按钮有没有、刷新失败怎么提示。心得这三步做完我会把“待确认项”单独列一栏。赛场上没法真的去问产品经理但你可以自己给出“假设”并在用例里注明“假设按 X 处理”。评委看到你有这个意识印象分直接上去了。2.2 用例设计方法的组合拳怎么打单用等价类会漏边界单用边界值会漏组合单用场景法会漏数据校验所以真实赛题上一定是组合用。我按优先级排一下第一顺位是等价类 边界值因为性价比最高。凡是涉及数值、长度、数量、日期的地方一律先划等价类再取边界。举个模拟赛常见的例子某输入框要求“数量为 1-999 的整数”。等价类划分就是有效等价类 1~999 的整数无效等价类分四种——小于 10、-1、大于 9991000、非整数1.5、非数字abc、空、特殊字符。边界值取 0、1、2、998、999、1000这六个点必测。第二顺位是判定表用于多条件组合的业务规则。比如“折扣计算”这种题会员等级普通/银卡/金卡× 订单金额100、100-499、≥500× 是否使用优惠券是/否三个条件组合起来 18 种情况每种情况算出一个期望折扣。判定表画出来每一列就是一条用例一条不漏。这里有个技巧先画全表再合并把动作相同的列合并掉能省一半用例量但合并要写在备注里说明“合并依据”否则评委会觉得你漏测。第三顺位是场景法用于端到端业务流程。主流程一条每个异常分支各一条。异常分支的挖掘口诀是“断、错、退、重”断网络中断、会话过期、错输入错误、数据异常、退中途取消、返回上一步、重重复提交、并发操作。第四顺位是错误推测法用来补漏。这个靠经验比如输入框粘贴超长文本、输入 emoji、浏览器后退后重新提交、修改 URL 参数越权访问、并发点击两次提交按钮、系统时间跨天时优惠是否失效。这些点在需求里通常不写但都是真实 Bug 高发区。我把这四种方法对应到一张速查表里赛场上直接照着走需求特征首选方法补充方法典型用例数单字段数值/长度校验等价类边界值错误推测8-12 条多条件组合规则判定表等价类按列数算通常 10-20 条流程/状态流转场景法状态迁移图主干 1 条 分支 6-10 条权限/角色判定表场景法角色数 × 操作数列表/分页/搜索等价类边界值错误推测8-10 条这里我要强调一点用例数量不是越多越好。模拟赛的评分逻辑通常是“覆盖关键测试点得分 冗余用例扣分或不加分”。我见过有人写了 80 条用例其中 40 条是重复的“输入正确值提交成功”把真正的边界和异常淹没了。宁可 30 条条条见血不要 80 条注水。2.3 一条能被评委看懂并复现的缺陷单缺陷报告这块很多人栽在“写给自己看”而不是“写给看不懂业务的人看”。模拟赛的评委可能是自动化判分也可能是人工看两种情况下结构完整、描述可复现都是硬指标。我用的字段是这样的字段填写要点反例缺陷标题模块操作现象一句话说清“有个 Bug”太笼统所属模块精确到子功能“订单模块”不够细严重程度致命/严重/一般/轻微按影响定全填“严重”优先级高/中/低按修复紧迫度定和严重程度混为一谈前置条件账号角色、初始数据状态留空复现步骤编号、可执行、每步一个动作大段文字糊在一起预期结果引用需求原文或明确规则“应该正常”实际结果客观描述现象可带截图“不行”无信息量附件截图/日志命名规范无严重程度和优先级的区分是高频扣分点。严重程度看影响面是否阻断主流程、是否丢数据、是否安全风险优先级看修复顺序是否影响上线、是否有替代方案。比如“订单列表页金额显示少了个小数点”是严重程度一般但优先级高“帮助文档链接 404”是严重程度轻微优先级低。这个区分你写清楚了评委一看就知道你是懂行的。复现步骤的写法我有个模板化思路每步只做一件事每步的状态可验证。比如使用测试账号登录系统进入“商品管理”页面点击“新增商品”填写商品名称“测试商品A”价格填“-10”点击保存观察页面提示与列表数据刷新页面重新进入商品列表查看该商品是否入库这四步的好处是第 3 步验提示第 4 步验数据落库两个维度都覆盖了。很多人的步骤只写到“点击保存”没写验证动作导致评委不知道你到底看到了什么。注意截图一定要截全屏或者截关键区域带上下文别只截一个小红字。我在实战里被坑过——只截了提示文字看不出是哪个页面、哪个操作触发的结果这条缺陷被判定“无法复现”直接作废。2.4 功能测试模块的常见坑第一个坑是只测正向。正向用例写起来顺手但分值低。赛题的测试点设计通常是正向 30%、反向 50%、边界 20%你把反向全漏了直接腰斩。第二个坑是优先级乱填。如果模板里有优先级字段一定要有区分度全填“高”等于没填。合理的分布是 P0阻断主流程10%、P1核心功能异常30%、P2一般50%、P3体验10%。第三个坑是用例步骤和预期结果不匹配。步骤里做了三个动作预期结果只写了一个评委没法判断你到底验了什么。原则是每个可观察的状态变化都要有一个对应的预期结果。第四个坑是忽略数据准备和清理。用例里写“输入已存在的用户名”但你得说明这个用户名是系统预置的还是你新建的。如果涉及数据修改还要说明测试后是否需要恢复否则后续用例会互相污染。3. 自动化测试题稳定性比花哨重要自动化测试模块一般给一个明确的操作流程比如“登录→进入某页面→新增一条记录→校验列表出现该记录→删除→校验列表消失”。要求你用 Python Selenium或者 Playwright把这段流程脚本化跑通并生成报告。看起来简单但这是丢分重灾区因为它同时考“能不能跑通”和“跑得稳不稳”。我的核心观点这个模块的评分标准本质上是“可重复执行”。一次性跑通不算本事跑十次十次通过才叫本事。所以你在写脚本的时候脑子里要一直绷着一根弦什么东西可能导致这次跑通、下次挂掉3.1 元素定位策略稳定优先简洁其次定位器选择上我的优先级是id 稳定的 data 属性 name 相对 CSS/XPath 绝对 XPath。绝对 XPath/html/body/div[3]/div[2]/...是自杀式写法页面结构一改就废而且赛题系统的 DOM 结构经常带动态生成的类名。如果页面元素没有 id我一般用“属性 文本”组合的相对 XPath比如# 推荐语义清晰抗结构变化 ADD_BTN (By.XPATH, //button[normalize-space()新增]) # 备选结合父级容器限定范围 ROW_BY_NAME (By.XPATH, //table//tr[td[normalize-space(){name}]])这里用normalize-space()是为了处理文本前后有空格或换行的情况很多系统按钮文字里带隐藏空格直接text()新增匹配不上这是个特别隐蔽的坑。还有个技巧定位器集中管理。不要把find_element的字符串散落在各处全部提到常量或者 Page Object 类里。这样一旦某个定位器失效你改一处就行赛场上时间宝贵别做全局搜索替换。3.2 等待策略显式等待是唯一正解time.sleep()是新手最容易犯的错也是评委一眼能看出来的低级问题。原因很简单固定等待要么不够网络慢就挂要么浪费每次都等满 3 秒20 个步骤就是 1 分钟。正解是显式等待等到条件成立立刻继续。from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC wait WebDriverWait(driver, 10, poll_frequency0.5) # 等元素可点击再点比等元素出现更可靠 wait.until(EC.element_to_be_clickable((By.ID, submit))).click() # 等列表里出现目标行而不是等页面加载完 wait.until(EC.text_to_be_present_in_element( (By.CSS_SELECTOR, #record-list), 测试商品A))超时设多少我一般设 10 秒。设太短3 秒在系统响应慢时误报设太长30 秒真出问题时要等很久才暴露。10 秒是个平衡点配合 0.5 秒轮询兼顾灵敏度和稳定性。更稳的做法是封装一个wait_and_click和wait_and_type把“等待 滚动到可见 点击 异常重试”打包在一起。有些元素被浮层遮挡直接点会报ElementClickInterceptedException先scrollIntoView再点能解决大半。def safe_click(driver, locator, timeout10): el WebDriverWait(driver, timeout).until( EC.element_to_be_clickable(locator)) driver.execute_script(arguments[0].scrollIntoView({block:center});, el) el.click()3.3 断言设计和数据驱动自动化脚本如果没有断言那就是“录制回放”跑完不知道对不对这是最典型的丢分点。断言要分层次页面级断言操作后是否跳转到正确页面、是否出现成功提示可以用 URL 包含某段路径或者提示文字出现数据级断言列表里是否新增了这条记录、字段值是否与输入一致状态级断言删除后该记录是否消失、总数是否减 1不要只做第一层。我见过脚本点完保存就断言“页面没报错”这等于什么都没验。数据驱动这块如果赛题要求批量跑多组数据用pytest.mark.parametrize是最省事的import pytest pytest.mark.parametrize(name,price,expect, [ (商品A, 99.99, 保存成功), (商品B, 0, 价格必须大于0), (商品C, -1, 价格必须大于0), ]) def test_add_product(driver, name, price, expect): page ProductPage(driver) page.add(name, price) assert expect in page.get_toast()这个写法有两个好处一是一组数据一个用例报告里清晰二是失败时能定位到具体是哪组数据挂的方便排查。3.4 自动化模块的三个高频事故事故一会话失效导致全局挂掉。很多系统有登录超时跑到后半段突然被踢回登录页后面全部报NoSuchElement。解决办法是在 fixture 里做“健康检查”——每次操作前判断当前 URL 或某个标志元素如果掉登录页就重新登录。事故二执行顺序依赖。新增依赖删除、删除依赖新增如果用例执行顺序被打乱就全乱套。解决方法是每个用例自己造数据、自己清理或者在 fixture 里做 setup/teardown别依赖上一个用例的残留状态。事故三报告没有失败证据。跑挂了评委和你自己都不知道为什么。加一个失败截图 hookpytest.hookimpl(hookwrapperTrue) def pytest_runtest_makereport(item, call): outcome yield rep outcome.get_result() if rep.when call and rep.failed: driver item.funcargs.get(driver) if driver: driver.save_screenshot(fevidence/fail_{item.name}.png)顺手把driver.page_source也存下来很多问题看源码一眼就明白了。实操心得赛场上如果时间紧先把“能跑通”的版本保存一份备份再做优化。我见过有人改重构改到跑不通又没备份最后交了个半成品。留一手比什么都强。4. 接口测试题别只盯着 200接口模块是这几个模块里“投入产出比”最高的——不需要处理页面渲染、不需要等待元素、跑起来飞快只要 HTTP 功底扎实分很好拿。但它也是最容易“自我感觉良好”的模块因为很多人把“状态码 200”当成了测试通过的唯一标准实际上 200 只说明服务没崩业务对不对完全是另一回事。模拟赛的接口题通常给一份接口文档或者让你自己抓包要求你对若干接口做测试覆盖正常参数、异常参数、边界值、鉴权缺失等场景最后输出测试结果。4.1 抓包和接口清单梳理如果赛题没给完整接口文档第一步必然是抓包。浏览器 F12 打开 Network 面板勾选 Preserve log先把主流程走一遍然后按 XHR/Fetch 过滤把所有业务接口列出来。列的时候不能只看 URL要记录四样东西请求方法、请求头重点看 Content-Type 和鉴权字段、请求体结构、响应体结构。整理成清单之后你才能看出接口之间的依赖关系。比如登录接口返回 token后续所有接口都要带这个 token查询列表接口返回 id详情接口要用这个 id。这个依赖关系直接决定了你的脚本结构——先调 A从响应里提取字段再传给 B。这里有个经常被忽略的点抓包时要看响应体里的业务码。很多系统 HTTP 状态码永远是 200真正的结果放在{code: 0, msg: 成功, data: {...}}里。你只断言 200等于什么都没断言。4.2 请求构造与三层断言我用 requests 写脚本时习惯做一个 session 级别的封装把 base_url、超时、公共头统一处理import requests class ApiClient: def __init__(self, base_url, timeout5): self.s requests.Session() self.base base_url.rstrip(/) self.s.headers.update({ Content-Type: application/json, User-Agent: autotest/1.0, }) self.timeout timeout def request(self, method, path, **kwargs): url f{self.base}{path} kwargs.setdefault(timeout, self.timeout) resp self.s.request(method, url, **kwargs) return resp断言我分三层写缺一层都算不完整def test_login_wrong_password(client): resp client.request(POST, /api/login, json{username: tester, password: wrong}) body resp.json() # 第一层HTTP 层 assert resp.status_code 200 # 第二层业务码层 assert body[code] 1001 # 第三层提示文案层用 in 而不是 避免文案微调导致误报 assert 密码错误 in body[msg] # 补充响应结构完整性 assert data in body第三层用in而不是是有讲究的。文案经常会微调比如“密码错误”变成“用户名或密码错误”用等号断言会误报用包含判断更稳。但也不能太松包含的关键词要能唯一标识这个错误类型。参数校验类的用例我一般用参数化批量跑import pytest pytest.mark.parametrize(payload,expect_code, [ ({username: , password: 123456}, 1002), # 用户名为空 ({username: tester, password: }, 1002), # 密码为空 ({username: a*65, password: 123456}, 1002), # 用户名超长 ({username: tester, password: 123456}, 0), # 正常 ]) def test_login_params(client, payload, expect_code): resp client.request(POST, /api/login, jsonpayload) assert resp.json()[code] expect_code4.3 鉴权、幂等与异常场景这三块是拉开差距的地方。鉴权测试不带 token、带过期 token、带伪造 token、用 A 用户的 token 访问 B 用户的数据越权。最后这个特别重要赛题经常埋这个点。验证方法很简单登录两个账号拿 A 的 token 去请求 B 的资源 id如果返回 200 且带回了 B 的数据就是水平越权漏洞。幂等测试同一个请求连续发两次看数据是否重复创建。比如提交订单接口连点两次是否生成两个订单。这个点用脚本很容易验发两次然后查询列表看数量是 1 还是 2。异常场景Content-Type 传错用 form 传 JSON、请求体不是合法 JSON、必填字段缺失、字段类型错误价格传字符串、超长字段、特殊字符和 SQL 关键字 OR 11只做输入校验层面的验证不做任何攻击性尝试。这些测的是服务端的健壮性正常系统应该返回明确的错误码而不是 500。注意异常测试要把握好边界。验证输入校验是否生效是正常测试行为但不要做任何可能影响系统稳定性的操作比如大量并发写、构造恶意 payload。赛场上一切以“证明功能行为是否符合预期”为目的克制很重要。4.4 接口模块的常见问题排查现象可能原因排查动作401/403token 未带、格式错、已过期打印请求头确认Authorization格式重新登录换新 token400请求体格式与 Content-Type 不匹配用抓包对比原始请求逐字段比对返回乱码响应未指定编码resp.encoding utf-8后再取resp.text断言一直失败但手工能过参数顺序、字段名大小写、空值处理差异打印实际响应体全文与预期逐字段对照依赖接口取不到字段JSON 路径写错、返回结构是列表先print(resp.json())看清结构再取最后一条我要多说一句。很多人取 token 写成resp.json()[token]实际结构是{data: {token: xxx}}直接 KeyError。养成习惯新接口先打印一次完整响应看清楚结构再写提取逻辑这个动作花 10 秒能省 10 分钟。5. 性能测试题线程数不是拍脑袋定的性能模块是很多人心里的“玄学”觉得压测结果飘忽不定、不好把握。其实性能测试的脚本部分非常标准化难点在于场景建模和结果解读——也就是“压多少”和“压完怎么看”。模拟赛的题目一般会给一个明确的性能指标比如“某查询接口在 50 并发下平均响应时间不超过 500ms错误率低于 1%”你要做的就是搭出这个场景并证明它达标或者不达标。5.1 线程数、Ramp-up、循环次数怎么算这是必须讲清楚的部分因为它是“有据可循”的不是凭感觉。先说并发数的估算。最常用的是利特尔法则Littles Law并发数 目标 TPS × 平均响应时间秒。举个例子业务目标是这个接口每秒处理 50 个请求实测单请求平均响应 0.2 秒那么需要的并发线程数大约是 50 × 0.2 10 个。考虑网络抖动和系统波动一般再加 20%~30% 缓冲实际设 12~13 个线程。如果题目直接给了“模拟 100 个用户同时在线”那就不能用利特尔法则了直接设 100 线程但要考虑 Ramp-up。Ramp-up 是“多少秒内把线程全部启动”设得太小比如 100 线程 1 秒启动会造成瞬时冲击曲线难看设得太大100 线程 100 秒启动又压不到峰值。经验值是Ramp-up ≈ 线程数 / 10 到 线程数 / 5100 线程就设 10-20 秒让压力平滑上升。循环次数怎么定如果要做持续时间型测试比如持续压 5 分钟用“调度器”配置持续时间循环次数勾选“永远”如果要做固定请求量测试比如总共发 1000 个请求循环次数 1000 / 线程数。我把常见的参数组合整理成表测试目标线程数Ramp-up循环/调度说明基准测试单用户11循环 10 次拿基线响应时间负载测试目标 TPSTPS × RT × 1.2线程数/10持续 5 分钟验证是否达标并发测试模拟 N 用户NN/10持续 3-5 分钟看高并发下是否劣化稳定性测试峰值 70%30 秒持续 30 分钟看内存/连接是否泄漏提示Ramp-up 不要设成 0JMeter 不允许也不要设成 1。1 秒启动 100 线程那种“瞬时冲击”测出来的数据没有参考价值因为真实用户不会在同一毫秒涌入。5.2 脚本搭建的关键元件JMeter 脚本我一般按这个顺序搭测试计划 → 线程组 → HTTP 请求默认值 → HTTP 信息头管理器 → 事务控制器 → 具体请求 → 断言 → 监听器。HTTP 请求默认值里填服务器 IP、端口、协议、编码UTF-8这样每个请求只写路径改环境时只改一处。信息头管理器里放Content-Type: application/json和鉴权头。如果需要先登录拿 token 再压业务接口就要用JSON 提取器做关联Names of created variables: token JSON Path expressions: $.data.token Default Values: NOT_FOUND然后在后续请求的头管理器里引用${token}。这里有个细节提取器的作用域要设对放在登录请求的子节点下否则可能取到空值。取不到的时候加一个调试取样器Debug Sampler把变量打出来看比猜快得多。断言我至少加两层响应断言状态码 200持续时间断言比如要求 500ms 内就设 Duration Assertion 500ms。持续时间断言很关键它能把“慢请求”直接标记为失败报告里一眼看出来。监听器方面聚合报告Aggregate Report和察看结果树View Results Tree是必须的但压测时要把结果树关掉它会把每个请求的完整响应存内存几百线程跑几分钟就 OOM 了。需要看单条请求细节时再临时打开。5.3 聚合报告怎么读才有说服力聚合报告的字段含义必须搞清楚不然写出来的分析就是废话字段含义关注点Average平均响应时间参考价值有限容易被极端值拉偏Median中位数50% 请求快于此值比平均值更能反映典型体验90% Line90% 请求快于此值核心指标反映大多数用户感受95% Line / 99% Line长尾指标看极端慢请求Min / Max最快/最慢Max 异常高说明有卡顿Error %错误率超过 1% 就要警惕Throughput吞吐量请求/秒与目标 TPS 对比写分析结论的时候不要只贴图。我见过太多报告就一张聚合报告的截图然后写“性能良好”。这种报告拿不到分因为没有任何解读。正确的写法是先给指标再给判断最后给原因推测。比如在 50 并发、持续 5 分钟的场景下查询接口平均响应 186ms90% Line 为 312ms最大响应 890ms错误率 0.02%吞吐量 268 请求/秒。90% Line 远低于 500ms 的目标判断达标。最大响应时间出现在压测开始后约 30 秒推测与连接池预热和 JIT 编译有关属于正常现象随后曲线趋于平稳。测试期间未观察到错误率随压力上升而增长说明系统在该压力下稳定。这段话里既有数据又有对比目标的判断还有对异常点的解释这才叫“分析”。评委看的就是这个。5.4 性能模块的坑坑一压测机自己成了瓶颈。GUI 模式跑高并发JMeter 自己就把 CPU 吃满了测出来的响应时间包含本机渲染开销数据不准。规范做法是用非 GUI 模式跑jmeter -n -t plan.jmx -l result.jtl -e -o report/跑完生成 HTML 报告。命令行跑出来的数据干净得多。坑二没有预热。前几十个请求往往特别慢连接建立、缓存未命中直接算进平均值会拉高数据。做法是先跑 30 秒预热然后清空结果再正式统计或者在报告里把前 30 秒的数据单独说明。坑三断言缺失导致错误率虚低。业务失败但 HTTP 返回 200没断言就统计不出来错误率显示 0%实际上大量请求业务失败。所以必须加响应断言检查返回内容里的业务码。坑四忽略被测系统的数据量。在只有 10 条记录的库上压查询跟在 10 万条记录上压结果天差地别。如果赛题允许提前把数据造到有代表性的量级如果不允许在报告里注明数据规模说明结论的适用范围。6. 单元测试与白盒覆盖率不是越高越好白盒/单元测试模块的分值通常不高但它有个特点——评分标准非常客观行覆盖率、分支覆盖率是机器算出来的不掺主观因素。所以这块是“该拿的分必须拿满”的类型。模拟赛一般给一段 Java 或 Python 的业务代码比如一个计算器类、一个订单金额计算函数、一个字符串处理工具要求你写单元测试达到指定的覆盖率并且测试用例要能发现代码里的问题。6.1 从代码结构反推测试用例拿到代码我的顺序是先读方法签名和分支再列测试点最后写代码。以一段“计算订单最终金额”的代码为例逻辑大概是基础金额减去优惠如果会员等级是金卡再打 9 折如果金额超过 500 免运费否则运费 10 元最终金额不能为负。这种代码里有四个分支条件两两组合就是 16 种情况但大部分可以合并。我在纸上先画一张分支条件表分支条件测试数据B1金卡 且 金额≤500等级金卡金额100B2金卡 且 金额500等级金卡金额600B3非金卡 且 金额≤500等级普通金额100B4非金卡 且 金额500等级普通金额600B5优惠后金额 0优惠1000金额100B6金额正好 500边界金额500B7金额 0边界金额0这七组数据能把所有分支都覆盖到。写的时候用参数化一组数据一行报告清晰。Python 版本import pytest from order import calc_final_amount pytest.mark.parametrize(level,amount,coupon,expect, [ (gold, 100, 0, 90), # 金卡9折加运费10 (gold, 600, 0, 540), # 金卡9折免运费 (normal, 100, 0, 110), # 普通加运费 (normal, 600, 0, 600), # 普通免运费 (normal, 100, 1000, 0), # 金额为负兜底为0 (normal, 500, 0, 510), # 边界正好500仍收运费 (normal, 0, 0, 10), # 边界0元订单 ]) def test_calc_final_amount(level, amount, coupon, expect): assert calc_final_amount(level, amount, coupon) expectJava 版本用 JUnit 5 的ParameterizedTest加CsvSource思路一样。注意金额用BigDecimal的时候断言要用compareTo而不是equals因为1.0和1.00的 scale 不同equals会返回 false这是个经典坑。6.2 覆盖率报告怎么看Python 用pytest --covsrc --cov-reporthtmlJava 用 JaCoCo 插件生成报告。报告里重点看三个指标行覆盖率Line Coverage执行到的代码行占比分支覆盖率Branch Coverageif/else 两个方向都走到的占比未覆盖行列表直接点进去看哪些行是红的我要说的是别为了刷覆盖率写无意义的断言。比如assert result is not None这种行覆盖率上去了但一行代码都没验证对错。评分细则里如果写了“覆盖率 断言有效性”这种写法反而扣分。更聪明的做法是先看未覆盖行再针对性补用例。跑一次覆盖率红色行就是你漏掉的逻辑分支通常都是异常路径除零、空值、越界补上这些覆盖率自然上去而且用例质量高。6.3 单元测试的注意事项第一测试方法要独立。不能 A 测试依赖 B 测试创建的对象每个测试方法自己造数据。用BeforeEach/ fixture 做初始化。第二处理好外部依赖。如果被测代码里有数据库查询、时间获取、随机数要 Mock 掉否则测试不稳定。Python 用unittest.mock.patchJava 用 Mockito。比如时间相关的逻辑Mock 成固定时间才能断言结果。from unittest.mock import patch from datetime import datetime patch(order.datetime) def test_expired_coupon(mock_dt): mock_dt.now.return_value datetime(2024, 1, 1) assert is_coupon_valid(20230101, 20231231) is False第三异常路径要单独断言。用pytest.raises或 JUnit 的assertThrows而且最好断言异常信息不只是异常类型。def test_divide_by_zero(): with pytest.raises(ValueError, match除数不能为0): divide(10, 0)第四命名要能自解释。test_1、test_2这种名字报告里根本看不出测的是什么。用test_金卡用户_金额600_免运费_实付540这种虽然长但一眼就懂。7. 时间分配和临场取舍这个部分没有任何文档会写但它是决定你能不能把所有模块都交上去的关键。模拟赛一般给 3-4 小时六个模块平均下来每个不到 40 分钟实际上不可能平均分配。我的分配思路是先拿确定性高的再啃耗时的。功能测试的用例设计和缺陷单只要你方法熟40 分钟足够而且分值稳定自动化脚本如果环境没问题45 分钟能跑通接口测试 30 分钟性能脚本 30 分钟加 15 分钟跑测试单元测试 25 分钟剩下 20 分钟做提交前的检查。但真实情况往往不按计划走。我给你几条临场判断的准则卡住超过 15 分钟就换赛道。比如自动化脚本的元素死活定位不到别死磕先保存现状去做接口和单元测试这两块不依赖浏览器稳。回头有时间再回来查。我在实战里见过有人在一个定位器上耗了一小时最后三个模块没做。性能测试的脚本可以先搭骨架再填肉。线程组、请求、断言先搭好能跑通一次就行压测数据可以边跑边写报告。因为压测本身要跑几分钟这段时间你可以干别的。报告类内容最后统一写。测试计划、测试总结这类文档不要一开始写等所有模块都做完你才有素材。写的时候直接引用各模块的数据效率高得多。提交物的命名和目录结构提前定好。我习惯用模块名_内容类型的命名比如功能测试_测试用例.xlsx、功能测试_缺陷报告.xlsx、自动化测试_脚本/、接口测试_集合.json、性能测试_报告.pdf。提交前对照题目要求逐条核对别因为文件名不对被判“未提交”。提示比赛结束前 10 分钟停止一切“优化”只做检查。检查项包括文件是否都能打开、脚本是否能在干净环境跑一次、报告里的截图路径是否正确、有没有把临时文件混进去。这几分钟的收益比再写十条用例高得多。最后说一个我自己踩过的坑别把测试数据留在被测系统里。有一次我压测造了几千条脏数据导致后面别人的功能测试用例跑不过虽然不影响我的分但如果评分是共用系统脏数据可能影响你自己后续模块的验证。压测前想好数据怎么清或者用独立的测试账号和标识。8. 常见问题速查表把前面散落的坑集中一下赛场上遇到问题可以先扫这张表现象大概率原因快速处置浏览器起不来报驱动版本不匹配Chrome 与 driver 大版本不一致换匹配版本或脚本里显式指定 Service 路径元素定位报 NoSuchElement未加等待、在 iframe 内、动态加载加显式等待switch_to.frame确认是否在新窗口点击报 ElementClickIntercepted被浮层/固定头部遮挡先 scrollIntoView 再点或用 JS 点击接口 401token 缺失/过期/格式错打印请求头核对重新登录接口断言失败但手工能过字段名大小写、嵌套层级、编码print(resp.text)看原始返回JMeter 跑高并发报 OOMGUI 模式 结果树全开改非 GUI 模式关闭结果树调大 HEAP压测错误率异常高断言过严、服务端限流、连接数超限放松断言看真实响应看服务端日志单元测试覆盖率上不去异常分支未覆盖看覆盖率报告红行针对性补用例单元测试金额断言失败BigDecimal 用 equals 比较 scale改用 compareTo报告提交后打不开相对路径失效、文件损坏用绝对路径引用截图提交前逐个打开验证这张表我会打印出来贴在显示器边上赛前过一遍赛中当查询手册。再补几个“非典型”的排查技巧。接口测不通的时候先用 curl 发一遍排除代码封装问题自动化跑不稳的时候把driver.implicitly_wait全部删掉只用显式等待因为隐式等待和显式等待混用会导致等待时间不可预期覆盖率突然下降的时候检查是不是有测试方法被跳过了Ignore或者 fixture 出错都会静默跳过。还有一个策略层面的建议赛题里如果给了示例或者模板一定要用。有些人觉得模板约束太多自己另起炉灶结果格式不符合评分标准。模板本身就是评分依据的一部分老老实实按模板填是最省事的选择。说点个人体会。这个赛项的题目设计有个很明显的特点它不追求“难题”追求“完整度”。单看任何一个模块难度都不高会点 Python、会点工具就能上手。但要求在时间压力下把所有模块都交出一份及格线以上的东西这就筛掉了一大批人。我见过技术很扎实的朋友因为时间没规划好最后只交了三个模块也见过技术一般但流程走得很顺的人总分反而更高。所以我一直觉得准备这个比赛最有效的方式不是刷题而是完整地做一次全流程演练——找个开源的 Demo 系统从需求分析开始走完用例设计、自动化、接口、压测、单元测试、报告掐着表做一遍。做完这一遍你对“哪一步会卡多久”“哪个模块该先做”就有直觉了。这种直觉在赛场上比任何技巧都值钱。另外就是心态。模拟赛的意义本来就是暴露问题题目解析看再多的“标准答案”不如自己动手把每一个坑踩一遍。我现在回头看自己第一次做这类题目的记录发现当时觉得“莫名其妙”的那些扣分点其实每一条都在提示同一个道理测试工作的价值不在于你跑通了多少而在于你能让多少人看懂你验了什么、怎么验的、结果意味着什么。把这个想明白了题目本身反而不难了。