省赛败北,佬们一路顺利——一次竞赛失利后的完整复盘与避坑指南
打出省赛赛场的门时,机器上的计时器还剩下四十分钟。看着其他队伍在紧张地打包代码和报告,我们三个人坐在工位上,谁也没有先开口。明明赛前准备了那么久,刷过的题、练过的环境、背过的命令,真到赛场上却像被一层雾罩住,关键时刻接二连三地出问题。最终的结果早在下午就已经有预感,提交界面显示的成绩远低于平时训练的平均水平。回来的路上,群里有人发了句“佬们一路顺利”,这句话像一根刺,扎了整整一周。
这篇文章不是获奖经验分享,而是一次失败者的完整复盘。我会把从报名、备赛、赛前准备、比赛当天的全过程,以及最终的失败原因,全部拆开来讲。里面包含实际踩过的坑、代码层面的教训、团队协作的问题,还有一套重新整理的省赛备赛路线。如果你正准备参加省级编程、软件测试或大数据相关的竞赛,这篇内容应该能帮你避开我们走过的弯路。
1. 赛前:从组队到备赛,我们做了什么
1.1 比赛背景
我们参加的是省级职业院校技能大赛中的软件测试赛项。比赛形式是团队赛,每队三个人,需要在规定时间内完成指定系统的功能测试、性能测试、自动化测试和白盒测试,最后提交测试报告。
比赛时长是一天,上午是环境配置和功能测试阶段,下午是性能测试、自动化脚本编写和报告撰写,最后还有一轮现场答辩。竞赛系统基于 Java Web 技术栈,被测系统是主办方提供的一个模拟商城项目,数据库使用 MySQL,测试工具限定使用 JMeter、Selenium 和 JUnit。
这里先说明一下我们的实际情况。三个人都是计算机相关专业,平时在课程里接触过 Java 和 MySQL,但对软件测试的理论和工具链接触不多。报名时,我们以为比赛考的是编码能力,所以把大量时间花在补习 Java 基础语法和 SQL 查询上。这个判断偏差,从一开始就为后来的失败埋下了伏笔。
1.2 备赛时间线
我们是赛前大约一个半月开始正式准备的。备赛计划分为三个阶段:
第一阶段(第 1~2 周),主要用于了解赛项规程和比赛工具。我们在网上找了一些往年的样题和模拟文档,初步了解了功能测试用例、缺陷报告、性能测试指标这些基本概念。这一阶段的主要成果是认识了比赛要考什么,但还没有真正动手操作过。
第二阶段(第 3~4 周),进入实际训练。我们搭建了 JMeter 和 Selenium 环境,用一个开源的电商项目做练习对象。功能测试用例写了大概一百多条,性能测试脚本调了三四轮,自动化脚本也写了一部分。但这个阶段我们暴露出一个很大的问题:三个人各有各的习惯,测出来的结果没有统一归档,缺陷报告格式也不一致,等到赛前才发现根本没法合并成一份完整的测试文档。
第三阶段(第 5~6 周),模拟训练和查漏补缺。我们按照比赛时间完整模拟过两次,每次都是三个人分工,一个写功能测试用例,一个盯性能测试,一个写自动化脚本。模拟成绩看起来还可以,但是细看会发现每次都有环节没做完,比如测试报告写得比较潦草,或者部分缺陷没有截图留证。我们当时没有足够重视这些“小问题”,觉得正式比赛时注意一点就好。事实证明,这些小问题不会自动消失,只会换一种形式在赛场上重新出现。
1.3 环境搭建中踩过的坑
赛前训练时,我们在环境上花了不少冤枉时间,这里挑几个影响比较大的说一下。
第一个坑是 JDK 版本问题。比赛机装的 JDK 是 1.8,而我们训练时用的电脑上装的是 JDK 17。JMeter 本身对 JDK 版本比较敏感,我们一开始用 JDK 17 跑出来的测试数据,和后来在 JDK 1.8 环境里跑出来的结果差别很大,尤其是响应时间指标。当时差点以为是脚本写错了,排查了半天才发现是 JDK 版本不同导致 JVM 参数和垃圾回收行为不一样。
第二个坑是 JMeter 分布式压测配置。比赛要求对被测系统进行性能测试,需要模拟一定数量的并发用户。我们用的是单机压测,但被测系统部署在本地虚拟机里,虚拟机的 CPU 和内存配置不高。一旦并发数超过一百,被测系统自身就成了瓶颈,响应时间暴涨,监控曲线非常不稳定。后来我们调整了虚拟机的资源配置,同时限制了 JMeter 的聚合报告采样范围,数据才勉强稳定下来。但比赛当天,机器配置和训练环境不同,这个坑又回来了。
第三个坑是 Selenium 浏览器的驱动版本。我们训练时用的 Chrome 版本比较新,对应的 chromedriver 也更新了。赛前忽略了比赛机的浏览器版本可能不同,结果比赛当天早上,自动化脚本在启动浏览器那一步直接报错,浪费了将近二十分钟才找到匹配的驱动版本。这种环境类问题在训练中一旦遇到,一定要记录到自己的环境清单里,而不是临时解决完就过去了。
2. 比赛现场实录:我们是怎么一步步落后的
2.1 上午的致命节奏问题
比赛当天早上八点半进场,九点正式开始。拿到试题后,我们按赛前模拟的分工迅速进入状态:A 同学负责功能测试用例设计,B 同学负责性能测试脚本,我负责自动化用例编写。
前一个小时还算顺利。功能测试用例的编写思路很清晰,按照需求文档把登录、注册、商品列表、购物车、下单、支付这些核心模块逐个过了一遍。但到上午十点半左右,问题出现了。被测系统在运行过程中出现了几个之前没有遇到过的异常,比如注册时邮箱格式校验在前端和后端不一致,购物车删除商品后刷新页面商品数量没有同步更新。我们花了很多时间讨论这些缺陷应该归到哪个功能模块,反而耽误了继续往下测的进度。
更严重的是,JMeter 性能测试开始了才发现,比赛机的网卡虚拟化策略和训练环境不同,压测时本机 IP 被限制并发连接数,导致测试结果里出现了大量连接超时。B 同学反复调整线程组参数,从 50 并发调大再调回,前前后后折腾了将近四十分钟。等性能测试的数据终于稳定下来,已经快十二点了,留给自动化测试的时间只剩下半天的一小半。
上午结束时的成果是:功能测试用例写了八成,但缺陷报告只提交了少数几条;性能测试脚本能跑,但数据收集不完整;自动化测试只完成了登录模块的脚本。整个上午的实际完成度,可能只到赛前模拟的六成。
2.2 下午的自动化崩溃
下午的自动化测试阶段,问题彻底爆发了。我们在赛前模拟中写好的 Selenium 脚本,在比赛机上无法直接运行。问题出在页面元素的定位方式。
训练项目用的是基于 Bootstrap 的老式前端模板,很多按钮是input标签配合class属性控制样式。而比赛提供的被测系统使用了 Vue 动态渲染,部分按钮在页面加载完成后才挂载到 DOM 树上,直接使用By.id()和By.name()定位不到元素。我们花了不少时间尝试各种等待方式,从Thread.sleep()到WebDriverWait,最终改写了大半的定位逻辑,才让基础流程跑通。
这个过程非常消耗时间。我们原本计划用 Selenium 覆盖登录、搜索、加购、下单、支付五个核心流程,最后只完成了前三个。支付流程涉及第三方接口的模拟,页面元素在支付成功后发生多次跳转切换,我们赛前没有准备这种场景的定位策略,赛场上也不可能临时想到完善的方案。
写到这里,我尤其后悔一点:我们在训练时没有实测过不同前端框架下的页面元素定位差异,默认只要脚本在自己电脑上能跑,比赛就一定没问题。这种侥幸心理,在竞赛中是致命的。
2.3 测试报告的仓促收场
下午三点半左右,开始写测试报告。按照评分标准,测试报告占很大的分数比例,包括测试环境说明、测试用例设计、缺陷报告、性能测试结果分析、自动化测试结果这几大部分。
但实际上,到这一步时我们手头的数据非常有限。功能测试还有很多模块没有覆盖到,缺陷虽然发现了十来个,但提交时只完成了部分截图和复现步骤,部分缺陷等级划分也不够准确。性能测试因为上午反复调参,最后导出的数据里缺少压测前后的环境基线对比,报告的完整性明显不足。自动化测试只有登录、搜索、加购三个流程的截图,支付部分没有能跑通,只能文字描述。
我们三个人分工写各自负责的部分,但报告格式和图表规范没有统一,导致最后拼接时出现了大量的重复与格式不一致。时间还剩半小时的时候,我们还在调整报告表格的对齐和图片排版,几乎没有时间回头检查测试数据的准确性。
最终提交的版本,是一个我们自己都清楚不太合格的报告。
2.4 答辩环节的准备不足
比赛最后一个环节是答辩。评委根据提交的测试报告,现场随机抽取问题提问。我们准备了一些常见问题答案,比如“你是如何设计测试用例的”“性能测试的指标有哪些”“自动化测试如何保证稳定性”。
但真正被问到的问题是:“被测系统的数据库出现了唯一约束冲突,你会从哪些层面分析这个问题的根因?”我们三个人面面相觑。这个问题涉及数据库约束、后端异常处理、并发控制等多个层面,我们的回答只停留在表面,甚至一度回答偏向了 MySQL 的DUPLICATE KEY语法细节,而没有从测试分析的角度给出系统性的排查思路。
赛后我们反复回想,这个问题的考察点其实非常清晰:一个合格的软件测试人员,不仅要能发现问题,还要能分析问题的产生链路,并对不同模块间的相互影响有全局认识。而我们的训练中,只练了“怎么测”,没有练过“为什么会出现这个问题”,更没练过“测出问题后怎么从架构层面去解释它”。
3. 赛后复盘:败因在哪里
3.1 技术层面的真实差距
比赛结束后,我们花了一个周末把赛题重新做了一遍,逐项对比评分标准,整理了技术层面的差距清单。
| 能力项 | 赛前自評 | 赛中表现 | 实际差距 |
|---|---|---|---|
| 功能测试用例设计 | 良好 | 中等 | 用例粒度不够细致,边界值设计不足 |
| 缺陷报告撰写 | 中等 | 较差 | 缺少系统性的缺陷分类与影响范围分析 |
| 性能测试脚本编写 | 良好 | 中等 | 对压测环境和被测系统瓶颈不敏感 |
| 自动化测试脚本 | 中等 | 较差 | 元素定位策略单一,缺乏健壮性处理 |
| 数据库SQL基础 | 良好 | 中等 | 对约束、索引、事务理解不透彻 |
| 测试报告编写 | 中等 | 较差 | 数据完整性不足,结论缺少依据 |
这组对比里,最大的差距不是“会不会用工具”,而是“有没有形成完整的测试分析思维”。赛前我们掌握的更多是独立的操作技能,比如怎么设置 JMeter 线程组、怎么用 Selenium 的findElement,但这些技能是零散的,没有串联起来形成一套从需求分析到测试设计再到缺陷追踪的方法论。
3.2 训练方法的核心问题
我们在备赛时犯了一个很典型的错误:过度关注工具操作,忽略了对被测系统的理解。
整个备赛过程中,我们反复训练的都是“如何用 JMeter 压测”“如何用 Selenium 写脚本”,但对被测系统的业务逻辑、数据库设计、接口交互流程关注较少。这直接导致比赛时,面对一个我们不熟悉的业务系统,无法快速拆解测试范围,也无法判断发现的异常是前端问题、后端问题还是数据问题。
如果重新准备一次,我会先花两到三天完整梳理被测系统的架构:前端框架是什么、后端接口有哪些、数据库表结构如何设计、核心业务链路是什么。只有对系统有了整体认识,测试用例设计才有依据,缺陷分析才能找到根因,性能测试的瓶颈分析也才能落到具体模块上。
另外一个训练方法上的问题是:我们没有建立自己的测试模板库。赛前写的功能测试用例、缺陷报告、性能测试报告都是临时拼凑的格式,没有统一的标准。比赛时一旦紧张,就会在排版和格式上浪费大量时间。正确做法是在训练初期就确定一套自己的模板,包括用例编号规则、缺陷等级标准、报告章节结构,之后每一轮训练都强制使用这套模板。
3.3 时间分配与团队协作的隐患
比赛的时间分配是一个非常值得复盘的点。我们现在来看,如果重新安排,上午应该优先保证“能稳定提交的完整成果”,而不是花大量时间追求“覆盖更多模块”。
比如,功能测试阶段,与其花半小时去讨论一个偶发缺陷到底该归为严重还是中等,不如先把核心流程的用例跑完、截图存证。又比如,性能测试阶段,第一次压测已经拿到了一组可用数据,就不应该反复调整参数追求“更漂亮”的曲线,而应该优先记录环境状态和结果,后面有时间再补充测试。
团队协作方面的核心问题是:三个人的分工边界太模糊。说是各管一个方向,但实际上功能测试和缺陷提交有重叠,性能测试和自动化测试都要操作被测系统,导致出现了“两个人同时改系统数据、另一个人跑测试用例”的情况,测试数据互相干扰,结果无法复现。
赛后我们统一了认识:团队赛的分工不能只看模块,还要看资源占用。比如,功能测试用例执行时是会修改系统数据的,而性能测试需要的是相对干净的数据环境,这两者的执行时间必须错开,否则数据一乱,所有测试结果都不可信。
3.4 心态和抗压能力
心态层面的问题,比赛中表现得很明显。上午的性能测试反复出问题时,B 同学明显变得急躁起来,频繁修改参数,每改一次就跑一次压测,结果越改数据越差。这种“应急式操作”是竞赛中最容易被忽视的大忌,因为每一次错误的调整都会消耗时间,而时间的流逝又会加大心理压力,形成恶性循环。
这个问题在后来的复盘里得到了比较清晰的答案:我们在训练中从来没有人为制造过“意外”场景。每次模拟训练,环境都是提前配好的,工具版本一致,被测系统运行正常,一切都按计划进行。这样练出来的心态是“只要跟着流程走就不会出问题”,而不是“出问题之后如何快速定位并止损”。
如果下次再参赛,我一定会在训练中主动加入故障演练:比如提前把 JMeter 版本换掉、把被测系统的某个接口停掉、在报告写到一半时让电脑内存告警,逼着自己习惯处理和预期不一致的情况。
4. 省赛备赛避坑指南
很多人写竞赛经验时只讲成功案例,但失败的教训往往更有参考价值。下面把我这次比赛中踩过的最有代表性的坑整理成一张对照表:
| 踩坑点 | 赛场表现 | 根因分析 | 解决建议 |
|---|---|---|---|
| 环境版本不一致 | 脚本无法启动、压测数据异常 | 训练环境与比赛环境脱节 | 提前通过官方渠道确认比赛环境,建立环境清单 |
| 页面元素定位失败 | 自动化脚本大面积报错 | 只练了老式前端,没覆盖动态渲染页面 | 训练中主动切换不同前端项目练习元素定位 |
| 缺陷报告格式不统一 | 报告拼接混乱,重复内容多 | 三个人各自为政,模板缺失 | 首周就确定统一模板并全程强制使用 |
| 性能测试反复调参 | 时间浪费,数据不完整 | 缺少“一次压测就拿到有效数据”的训练 | 训练时规定只能调整两轮参数,其余靠分析 |
| 数据库相关问题答不上 | 答辩失分 | 对数据库约束、事务、并发理解浅 | 补充数据库原理层面的系统学习 |
| 时间分配失衡 | 报告仓促收尾 | 前面环节超时没有止损机制 | 赛前制定时间节点清单并严格执行 |
这张表里的每一条,都是我们用一场比赛付出的代价换来的。如果你正在准备类似的比赛,可以对照检查自己的备赛过程。
5. 下一轮备赛的技术路线
如果接下来重新准备一轮,我会按照下面这个路线来安排训练。
5.1 第一阶段:工具和基础能力(第 1~2 周)
这一阶段的目标是快速掌握比赛工具的基本用法,但不追求深入。
- JMeter:线程组、参数化、断言、聚合报告、监听器。
- Selenium:元素定位、常用等待、截图、TestNG 或 JUnit 集成。
- MySQL:增删改查、多表查询、约束、索引、事务基础。
- Java 基础:面向对象、集合、异常处理。
示例:用一分钟快速创建一个最简单的 JMeter 测试计划。
# 在 JMeter bin 目录下启动 GUI ./jmeter然后在测试计划中添加一个 HTTP 请求,访问被测系统首页,添加聚合报告监听器,运行后查看响应时间、吞吐量等指标。这个阶段不需要追求复杂,重点是让每个工具都能跑通。
5.2 第二阶段:系统化用例设计(第 3~4 周)
这一阶段的核心是建立测试设计思维,而不是再学新工具。
训练内容:
- 功能测试用例编写,使用等价类、边界值、场景法、错误推测法。
- 缺陷报告的完整撰写,包含标题、前置条件、复现步骤、预期结果、实际结果、优先级和严重程度。
- 性能测试场景设计,包括负载测试、压力测试、稳定性测试的区分。
这里给出一个功能测试用例的示例模板:
用例编号:TC-LOGIN-001 测试名称:登录功能-正确用户名和密码 前置条件:注册用户 user01,密码为 123456 测试步骤: 1. 打开系统登录页面 2. 输入用户名 user01 3. 输入密码 123456 4. 点击登录按钮 预期结果:登录成功,跳转到系统首页 实际结果:(待填写) 缺陷等级:(待填写)不要小看这种模板化的写法,它能在比赛中帮你节省大量时间,也让报告的完整性更有保障。
5.3 第三阶段:综合模拟与故障演练(第 5~6 周)
这一阶段只做一件事:模拟比赛。
模拟时要注意三点:
第一,严格按比赛时间执行,到点必须交卷,不能出现“再给我十分钟就写完了”的情况。第二,每次模拟都要换一个不同的被测系统,可以从 GitHub 上找开源项目,提前感受不同技术栈下的测试差异。第三,模拟结束后必须做复盘,把失败点记录到问题清单里,下次模拟前重点检查。
第三周开始,每周加入至少一次“故障演练”,具体做法是:
# 模拟环境故障:将被测系统端口占满 # 在 Linux 终端执行 for i in $(seq 1 100); do curl -s http://localhost:8080 > /dev/null & done # 此时再用 JMeter 执行压测,观察连接超时和响应时间变化 # 要求:快速定位是环境问题还是脚本问题这种训练能锻炼对系统状态的敏感度。比赛中最怕的不是出错,而是出错之后分不清是自己脚本的问题、系统的问题还是环境的问题。
5.4 技术栈的延伸学习
除了比赛直接用到的工具,我们还应该补三块底层知识:
- 数据库原理:事务隔离级别、锁机制、索引失效场景、慢查询分析。
- 操作系统基础:进程、线程、内存、文件描述符、CPU 和内存监控。
- 网络协议:HTTP 请求响应模型、Cookie 与 Session、TCP 连接复用。
这三块知识不会直接出现在赛题操作里,但它们是分析问题的底层工具。比如性能测试中的连接超时问题,如果不懂 TCP 连接数限制,只会盲目调高 JMeter 的线程数,结果只会更糟。
6. 给后来者的一些建议
如果你正在准备比赛或者正打算报名,下面几条是最想让你知道的:
第一,明确比赛到底考什么。花一周时间把所有官方文档、往年样题、评分标准吃透,比盲目刷十天工具教程更有价值。很多队伍(包括我们)直到比赛前一周,才真正弄明白评分侧重点。
第二,版本和环境问题就是分数。比赛当天最不值钱的失误就是环境类问题。统一 JDK 版本、Chrome 版本、数据库版本,提前到比赛场地踩点测试,这些细节一定要做充分。
第三,用例设计能力是基本功。工具只是载体,真正拉开分数差距的,是同一个功能模块你能想到多少条用例,边界覆盖有多全面,缺陷分析有多深入。平时可以拿自己学校的系统练习,比如教务系统、图书馆系统、选课系统,都是很好的测试对象。
第四,不要忽视团队协作。三个人之间信息要透明,谁的测试数据会影响谁,谁的操作会占用共同的被测系统,这些都要在赛前明确,形成一套约定。比赛不是单兵作战,配合失误的代价比技术失误更大。
第五,失败不是终点。省赛只是竞赛道路上的一个节点,不是全部。一次失利暴露的是准备层面的问题,不一定是能力天花板。把失败的原因拆透,反而能让下一轮备赛更有方向。
7. 写在最后
打完最后一个收尾字符,回想这一整轮比赛,我最深的感触是:竞赛的真实难度,不在于题目本身有多难,而在于你能否在有限的时间内,稳定地输出平时训练中已有的水平。我们输,不是输在了不会用某个工具,而是输在了准备时对“不确定性”的估计不足。环境会变,系统会变,题目会变,只有提前覆盖了这些问题,赛场上才能稳住。
离开赛场时,看到朋友圈里另一支队伍发了张合影,配文是“省赛结束,佬们一路顺利”。我知道他们说的“佬们”并不是我们。但换个角度想,这也是个好兆头——把“佬们一路顺利”送给继续奋战在实验室里的每一个选手,也送给下一次还会站到赛场上的自己。
下一次,我们会准备得更充分一点。