
前几天刚交付了一个抽奖系统的测试报告趁热打铁把这个过程完整梳理一遍。这种任务看起来很单一真正做起来才发现牵扯的东西比想象中多得多。抽奖系统看起来就是“点一下按钮转个圈出个结果”但藏在后面的业务规则、库存扣减、并发控制、防刷策略每一环都可能出问题。这篇就按我实际执行的思路来写从需求拆解到最终报告输出包括中途踩过的坑和排查过程希望能给同样在做活动系统测试的同行一些参考。这次测试对象是一个典型的有奖促销系统用户在活动期间消耗积分或抽奖次数参与抽奖奖品池分等级用户每天有抽奖次数限制中奖概率分奖品梯度设置。系统需要支撑短时高并发访问同时在活动结束后能够导出中奖记录、完成奖品发货。听起来不复杂但把规则细化到可测试状态工作量立刻上来了。1. 接到任务后的第一件事需求拆解与测试范围确认1.1 抽奖系统到底测什么不是只有“点一下”测试报告要落地第一步不是打开工具写用例而是先搞清楚这个抽奖系统的业务规则。很多测试新手拿到任务就直奔功能测试结果测到一半发现规则理解错了全部白做。我这次接了任务后先拉着产品过一次需求文档列出所有和“抽奖”相关的行为路径用户怎么获得抽奖机会、抽奖时先校验什么、奖品库存如何扣减、中奖后如何领取、活动时间如何控制、未中奖有没有提示以及后台怎么查看记录和统计数据。把这些路径画出来之后测试范围内核就清楚了用户端抽奖主流程是核心但后台的规则配置、库存管理、中奖记录导出、活动上下线操作同样不能漏。我通常会把测试范围分成功能、性能、安全、兼容四块然后分别设计用例。功能测试聚焦业务流程和异常场景性能测试聚焦并发和峰值压力安全测试聚焦防刷、越权和数据一致性兼容性测试聚焦不同终端和浏览器的可用性。测试范围确认好后面的执行才不会乱。这个阶段有一件事值得单独提一下抽奖系统最常见的需求描述是“随机中奖”但“随机”两个字背后有不同的业务语义。有的是均匀概率抽奖也就是每个奖品按固定概率命中有的是权重抽奖根据奖品库存实时调整权重还有的是游戏化抽奖比如九宫格、大转盘不同格子对应不同奖品。测试之前必须明确系统采用哪种策略否则概率验证无从谈起。我这次遇到的系统属于第二种——权重抽奖规则配置在后台奖品概率之和可以动态变化这给测试带来了额外的校验成本。1.2 测试环境与数据准备怎么搭一个够用的“战场”抽奖系统测试离不开数据准备。环境上至少需要一套独立的测试环境不能拿生产环境直接试。我一般会要求环境具备这几个条件数据库、缓存、应用服务版本与生产保持一致后台配置了完整的奖品池、活动时间、抽奖规则有模拟用户体系可以批量造用户。如果被测试系统是微服务架构还要确认依赖的积分服务、用户服务是否可用。数据准备上我习惯分三类来造第一类是正常业务数据比如有足够数量的用户账号、不同等级的奖品库存、合理的积分余额第二类是边界数据比如用户抽奖次数刚好到上限、奖品库存只有1件、活动开始前10秒和结束后10秒的请求第三类是异常数据比如伪造的奖品ID、不存在的用户、重复的抽奖请求标识。边界和异常数据往往能提前暴露系统问题比常规数据价值更高。奖品库存是抽奖系统最容易出问题的地方。我在测试环境里会刻意把库存设置得比较小比如头奖库存只有3件然后并发去抽用这种极端方式验证扣减逻辑。曾经测过一个模拟项目就是靠这种方式发现了库存超发的严重缺陷用户端显示中奖了后台记录里却找不到库存消耗记录。后面再讲到并发测试时会详细展开。2. 功能测试从规则配置到异常场景的全链路梳理2.1 核心功能测试点拆解机会数、中奖率、库存、流程一个都不能少功能测试是整个报告的基础也是最容易返工的部分。抽奖系统的功能测试我通常按四个维度来拆用户抽奖入口、抽奖机会管理、抽奖结果处理、中奖后发放链路。每一个维度都不能只测主路径得往下钻细节。用户抽奖入口主要验证从不同入口进入时规则是否正确。比如用户从商品详情页和活动页进入抽奖入口参数会带不同的活动ID如果后端用写死的活动ID就可能出现A活动抽成B活动奖品的问题。这个点我专门测过真实遇到过由于活动ID透传错误导致的串奖问题所以入口参数传递的校验务必纳入用例。抽奖机会管理是抽奖系统的灵魂。规则一般包含每日限制、总量限制、任务获得等。我这里遇到的规则是用户每天签到获得1次单日累计消费满特定金额再送1次每个用户每天最多抽5次活动周期内总共最多20次。测试的时候要重点验证每日零点重置逻辑参与高峰期用户跨时段抽奖请求处理是否正常以及次数用尽后是否有明确提示。为了验证重置逻辑我在测试环境特意改了服务器时间模拟零点前后同时发送抽奖请求的场景检查数据库里用户剩余次数是否被正确刷新有没有出现“今天抽了5次过了零点还是5次”的缺陷。再聊抽奖结果处理。这里的核心是概率和库存计算的准确性。抽奖系统通常有一个概率配置表后台按奖品ID配置权重前端展示时可能还有个“中奖概率百分比”后端要真正按这个概率计算。测试时我建议把概率配置表和数据里实际产生的中奖率做对比下文会专门说概率验证方法。库存扣减还有两种常见设计事前扣减和事后扣减。事前扣减是用户点抽奖时就预占库存流程中如果用户放弃领奖要回补库存事后扣减是中奖后才扣库存。两者各有优劣但不管哪种测试的核心问题都是同一件事库存会不会多扣、少扣、重复扣。中奖后发放链路通常不是抽奖系统自己独立完成的它会联动积分核销、订单中心、物流系统。测试时要关注中奖记录到待发货状态流转、通知推送、以及用户主动放弃奖品时数据状态是否一致。我在测试中发现过一个问题用户中奖后未填写收货地址系统后台显示该奖品已是“已发货”状态但用户端仍提示“待填写地址”后来定位到是状态同步接口遗漏了异常分支。这类问题不产生崩溃但影响非常坏也暴露了状态机测试覆盖不足。2.2 边界条件与异常场景真正容易翻车的都在这功能测试的主路径一般都比较稳定问题高发区集中在边界和异常。抽奖系统常见的边界条件至少有五类活动时间边界、抽奖次数边界、库存边界、并发边界、参数异常边界。每一类我都单独设计了一组用例。活动时间边界要覆盖活动开始前、开始瞬间、结束瞬间、结束后。使用场景包括活动未开始时用户是否可以访问页面但不能参与活动进行中是否有逻辑漏洞导致无限抽奖活动结束后后端是否拒绝所有抽奖请求。这里特别容易出问题的是分布式环境下的时间同步如果应用服务器和数据库服务器时间差超过一秒活动开始瞬间的判断就可能错位导致部分请求放行部分拒绝。次数边界测试中我把“剩余0次”“剩余1次”“已抽满每日上限”“已抽满总上限”都分别造数据执行。发现过一个典型问题当天抽奖次数用尽后用户通过浏览器地址栏手动构造请求后端没有拦截仍然返回了“抽奖成功”的响应。这个问题本质是前端隐藏了按钮但后端缺少校验。所以我只提醒一句抽奖系统的前端展示能绕过所有关键限制必须后端验证前端限制只是体验层。库存边界这里用的是“库存为0”“库存为1”“剩余库存小于并发请求数”三种场景。库存为0且未中奖的情况比较简单难的是“最后一件奖品同时被多个请求命中”这就要看库存扣减的原子性了。后来安全与一致性部分会细讲。参数异常测试包括缺少用户ID、缺少活动ID、奖品ID不存在、请求次数为负数、活动ID与用户积分不匹配等。这类用例的价值在于发现系统是否因为参数异常返回了不该返回的业务数据。我测试过的一个系统在传入负的抽奖次数时竟然把用户抽奖次数增加了一次属于很典型的参数校验缺失。2.3 概率验证思路靠手工点按钮永远验不出来抽奖系统的“中奖概率”如果只靠手工抽几十次就下结论是不严谨的。概率验证必须具备数据基础。我采用的做法是写脚本模拟批量抽奖直接用接口调用绕开前端统计各种奖品的中奖次数再和期望概率对比。脚本核心逻辑非常简单就是一个概率判定循环但非常实用。import random # 模拟奖品概率假设权重列表 prizes [ {name: 一等奖, weight: 1}, {name: 二等奖, weight: 9}, {name: 三等奖, weight: 90}, ] weights [p[weight] for p in prizes] total sum(weights) counts {一等奖: 0, 二等奖: 0, 三等奖: 0} trials 1000000 for _ in range(trials): r random.uniform(0, total) cumulative 0 for p, w in zip(prizes, weights): cumulative w if r cumulative: counts[p[name]] 1 break for name in counts: print(name, counts[name] / trials)用这个脚本先算出理论上当前的随机数分布再用线上接口做N万次模拟将接口统计结果与理论值对比。如果两者偏差在置信区间内说明概率模块逻辑正常如果偏差明显说明权重计算有问题或随机种子设计不理想。我在一次测试中把接口的模拟中奖率跑到了约1.4%而期望是1%后来定位到权重配置表里把一等奖权重写成了1.4而不是相对权重1。所以说概率配置表的核对必须高度重视不能只看系统里的百分比数字。概率验证这个环节的难点不是写脚本而是样本量要足够。抽出100次就下结论说中奖率不准确是直接暴露测试不专业的行为。压测时用千万级请求做概率统计是不现实的容易对下游依赖造成过大压力我在实际操作中会控制在10万到50万次之间视系统接口性能而定。对误差分析用正态分布近似的置信区间简化判断简单有效。3. 性能与稳定性测试别让奖品在高峰时刻“消失”3.1 性能测试需求分析与压测模型设计先搞懂峰值模型再动手抽奖系统的性能测试目标不是“测出最高QPS”而是要知道系统在预期业务峰值下表现如何资源是否够用有没有雪崩风险。所以分析需求阶段就要确认几个数字预计同时在线参与人数、活动开始高峰持续时长、单个用户平均抽奖次数、接口预期最大QPS。拿到这些数据后才能设计出合理的压测模型。以这次的活动为例预估活动开始10分钟内会有两万人同时访问抽奖接口峰值QPS按2000设计读接口查询中奖记录、查看活动信息不做过高要求因为这类型系统瓶颈集中在抽奖接口。基于这个模型我把性能测试拆成三个层次单接口基准性能测试、核心流程混合场景测试、峰值持续稳定性测试。单接口测试看抽奖接口极限混合场景按照真实用户行为比例模拟访问路径持续测试重点验证长时间高负载下系统资源是否平稳。压测工具有很多我这次用的是开源工具在测试节点上跑压测节点与测试环境同机房避免网络抖动干扰数据。并发线程数和持续时间按阶梯递增一般会先跑一个5分钟预热再按200、500、1000、2000并发逐步加压每个阶段观察响应时间、错误率和服务器资源指标遇到拐点立刻记录。不是直接上2000并发一次性测试否则容易混淆瞬时冲击和持续负载的差异。3.2 数据库与缓存层的隐性风险性能问题往往藏在下游抽奖接口单次逻辑看似轻量但压力一大最先崩的通常是数据库和缓存。我在这次测试中遇到过一个非常典型的性能瓶颈抽奖接口每次请求都会去查一次用户账户表同时还会更新抽奖次数当并发上升到1500时数据库连接池被打满接口响应时间从50毫秒飙升到8秒。排查时先确认缓存是否生效结果发现抽奖次数的查询走了数据库没有走缓存。后来项目组把“用户剩余抽奖次数”从数据库查询改为缓存查询并设置合理的过期时间连接池压力大幅下降。这是一个很常见的设计问题测试人员在性能分析时一定要看接口的调用链不能只看应用本身的CPU和内存。还有一个典型的隐性风险是奖品库存扣减的事务范围。如果事务里包含远程调用比如通知消息、记录发货单事务时间会被拉长锁定的数据库记录也久性能就会恶化。我在测试环境中构造过“库存扣减发送站内通知”在同一事务里执行的场景并发到800就已经频繁出现超时。这种问题一般需要开发优化事务边界测试报告里要给出推动结论而不是仅仅记录问题现象。性能测试过程中发现的问题要分级记录影响系统正常使用的优先修复不影响主流程但可能拖垮数据库的要列为需要优化项。最终报告包含响应时间分布、TPS趋势、CPU/内存/磁盘IO曲线以及全链路调用耗时明细。业内常说性能测试不是为了找极限而是找“预估流量下的系统表现”这句话放到抽奖系统场景里尤其适用活动结束前系统崩溃的后果是所有环节都不愿意承担的。4. 安全测试奖励再好也不能让人“薅”穿4.1 接口防刷与越权抽奖系统最容易被人写脚本“薅羊毛”安全测试在抽奖系统里不是可选项至少要把防刷和越权放在核心位置。接口防刷就是防止用户通过脚本批量请求抽奖接口绕过前端限制无限抽奖。测试时先验证是不是只依赖了前端按钮置灰如果是那么只要用脚本直接调用后端接口就能轻松突破次数限制。扫描接口时还要关注抽奖接口是否有频率限制比如同一IP每秒最多允许几次请求同一用户每分钟最多允许多少次。我这次测的系统中抽奖接口在网关层做了频控但频控只针对单IP没有针对用户维度。结果就是普通用户拿工具切不同代理IP照样能刷直到用户维度的抽奖次数校验兜底才拦住。但这又验证了之前的结论后端校验是否存在不严谨通常要在安全测试阶段反复验证。所以用例设计时我会分别用“同一用户不同IP”“同一IP不同用户”“同设备伪造不同用户”三种姿势去试。越权测试要关注水平越权和垂直越权两种。水平越权比较典型的是A用户查看B用户的中奖记录、修改B用户的收货地址。抽奖系统里常见的水平越权点在奖品领取和记录查询。实测发现过一个系统通过用户ID参数查询中奖记录时后端没有校验用户身份与ID是否匹配只要把参数改成别人的ID就能看到别人的手机号和地址这是严重隐私漏洞直接阻断上线。垂直越权则是指普通用户可以访问管理员后台接口比如自己给自己发奖品这种问题通常发生在后台接口没有做角色校验的情况下。防刷策略测试的另一个维度是验证“风控策略是否会误杀正常用户”。很多系统为了防止刷单设置了过于激进的频率限制导致正常用户快速点击也被拦截。我在测试中会模拟快速点击5次观察正常反馈是否出现“操作过于频繁”的提示以及提示是否友好、策略是否合理。既要防住恶意又要保证普通用户体验这个平衡点也是报告中的一个重要结论。4.2 数据一致性与幂等验证并发中奖之后库存不能变成负数抽奖核心动作是扣减库存数据一致性缺陷的直接表现就是奖品超发和库存负数。为了验证这一点我专门设计了一组并发请求测试设置一等奖库存为1模拟10个用户同时请求抽奖理论上只有1个人能成功中奖。最初测试结果非常直观地暴露了问题10个请求全部命中一等奖后台库存变成了-9。这就是典型的“并发读同一库存、各自扣减、最后写回”引起的覆盖错误本质是缺少行锁或乐观锁版本控制。后来系统通过数据库乐观锁版本号机制修复每次更新库存时校验版本号不一致则重试或放弃。修复后再跑同样的并发用例只有1个请求成功其余9个都返回未中奖库存正确归零。幂等验证也是抽奖系统的一个关键项。用户连续点击多次抽奖按钮或者前端重试机制触发重复请求后台要能识别出这是同一次抽奖请求不能因为重复请求就多发一次奖品。测试方法很简单用同一个请求ID连续发两次抽奖请求观察后台是否出现两条中奖记录。我发现过一个系统在接口超时重试时由于缺少全局唯一请求ID校验导致同一用户在同一秒生成了两条中奖记录并且都扣了积分。后来增加了请求幂等键基于用户ID、活动ID、时间段生成的唯一标识重复请求直接返回首次结果。数据一致性和幂等测试涉及的核心不是“接口返回什么”而是“数据库最终是什么”。测试报告里要写明具体的验证结果比如“库存从100到99中奖记录只生成1条用户积分只扣减1次”这样的结论对开发定位问题最有价值。自动化脚本在这个环节很吃香10个并发用户可以手动模拟100个并发请求就不现实了所以我的实测脚本基本都是用Python并发库构造并发请求统计返回状态并核验数据库变化。5. 兼容性测试与最终报告输出让结论能指导上线5.1 多端兼容与用户体验抽奖页面不是“能点就行”兼容性测试主要是确认抽奖系统在不同终端、浏览器和操作系统下都能正常使用。抽奖活动通常分享到聊天软件再通过内置浏览器打开所以微信内置浏览器、主流手机浏览器、PC端浏览器是必测环境。重点检查的是抽奖动画是否卡顿、按钮是否错位、支付或积分核销流程是否顺畅以及不同分辨率下的页面展示。我这次测到一个非常隐蔽的兼容性问题某型号手机在微信内置浏览器里抽奖转盘动画执行到最后一步时白屏用户等了很久页面才恢复。原因是该浏览器内核不支持动画库里的某个CSS属性导致动效线程卡住。后来改成兼容该内核的回退方案问题解决。这类问题只在特定浏览器出现如果没有覆盖这部分测试上线后会收到大量用户投诉。除了页面兼容还要验证接口层面的兼容性不同版本客户端调用的接口路径是否一致旧版本客户端在活动结束后是否还能正常请求。曾经遇到一个系统活动规则更新后旧版本客户端传递的参数结构没有跟着变化后端因为参数缺失直接返回500导致一批用户无法进入抽奖页面。这个教训提醒我兼容性测试要同时关注页面和接口二者缺一不可。兼容性测试的用例设计思路是“矩阵覆盖”设备矩阵、浏览器矩阵、网络矩阵。设备矩阵选择主流型号各一台做页面展示和主流程验证浏览器矩阵覆盖最新版本与上一版本网络矩阵覆盖WiFi、4G/5G、弱网场景。时间有限时可以优先保证微信内置浏览器和主流手机浏览器的核心流程其余做抽查并在报告中明确测试覆盖度。5.2 测试报告怎么组织才算合格缺陷分级、数据、结论一个不能少测试报告是整个测试流程的最终交付物它的价值不是“记录做了什么”而是让项目组知道“能不能上线、上线带什么风险、必须修复哪些问题”。我习惯把报告组织成这几部分测试范围与实际执行情况、功能测试用例统计、缺陷统计与分级分析、性能测试结果、安全测试结果、兼容性测试结果、风险评估与上线建议。缺陷分级这事特别重要。抽奖系统的缺陷分级规则我按严重程度分四层阻断性问题比如奖品超发、用户隐私泄露、全链路崩溃严重问题比如某个机型无法抽奖、并发时概率异常一般问题比如提示文案有误、页面布局错位建议类问题比如体验优化点。报告中要把每个级别的问题数量、修复状态、影响范围写清楚并给上线结论。数据部分要包含全量测试数据。功能测试覆盖用例总数、通过率、失败项性能测试的TPS、响应时间、错误率、资源使用率安全测试的漏洞数量及风险等级兼容性测试的矩阵覆盖结果。数据本身不说明问题需要配合分析和建议例如“性能峰值期间数据库连接池使用率95%建议扩容或优化连接池配置”这样带明确动作的结论。报告里还要包含复测结果。不能只报告“发现了问题”还要跟踪这些问题修复后是否通过回归测试。我一般会在报告最后附上回归结论表列出每个缺陷的发现时间、修复时间、复测状态这样整个测试过程的闭环一目了然。上线建议分为“建议发布”“修复不阻断类缺陷后可发布”“暂不建议发布”三种这个结论必须鲜明不能模糊。测试报告不是形式文档它是上线前最后一道关卡的具体表达。就身边一些同事的反馈来看最容易引起争议的其实是“测试范围和未覆盖部分说明”。抽奖系统因为业务规则复杂测试不可能穷尽所有组合但报告中如果只写“测试完毕”而没有说明遗漏了什么对上线决策是不负责任的表现。我会在报告中明确写出“未经覆盖的测试项”及原因比如“旧版本客户端接口兼容未覆盖到XX版本原因是该版本已不在支持范围”这样项目组对剩余风险一目了然。最后再分享一个实际经验抽奖系统的测试报告里功能测试那部分做得再细也不如安全测试和并发测试更能说服人。原因很简单几乎所有抽奖活动的重大事故都在并发超发和羊毛党刷量这两个环节而这两块恰恰是普通功能用例测不出来的。我后来做这类项目时都会把安全用例和并发用例放到最高优先级去执行把概率验证作为功能测试的必选项。希望这篇梳理能让同行少走一些弯路。