Tempcase 测试笔记
验证码重发测试:
把每封信对回一次请求
点了两次重发,先收到的却是第二封。先别把「最新到达」当作「最新签发」:把请求、发送事件与收件记录连起来,才能判断到底是哪一步出了问题。
验证码邮箱能证明一封信被接收,也能让你检查正文;它不能替业务系统决定哪个码有效。本文以你有权测试的预发环境为前提,使用不承载真实资产的测试账号。示例中的编号均为说明用代号,不是线上故障记录。
2026 年的自动化回归,为什么还会把两轮认成一轮
自动化脚本常把流程写成「申请验证码 → 等待邮件 → 取最新一封 → 提交」。单次运行正常,并不代表连续重发也可靠:第一封还在队列,第二次请求已经完成;两个窗口共用一个账号,脚本却只保存了最后一次点击时间。
此时收件箱里的最新一封可能属于较早请求。只按主题、未读状态或到达顺序取信,会把投递乱序误报成验证码错误,也可能用错码碰巧通过而漏掉缺陷。测试注册邮件,首先要建立对应关系,而不是先写一个抓六位数字的正则。
先确定重发规则,不能由收件箱猜答案
在跑验证码重发测试前,向产品和后端确认一份可执行的规则:重发是复用仍有效的码,还是签发新码?新码何时撤销旧码?有效期从首次签发还是本次签发计算?规则作用于账号、用途,还是某个验证会话?
先写预期,再制造乱序
「仅最新码有效」和「有效期内多个码均可用」是不同设计。后者不应仅凭旧码通过就被判成缺陷;但两种设计都需要定义尝试次数、限流、过期与成功后的一次性消费规则。
把规则版本写进用例。若规则尚不明确,先记录待确认项,不要让自动化断言替团队做产品决定。本文后面的复现示例明确采用「新码签发成功后,旧码立即失效」。
一轮一个 case:地址只是上下文的一部分
从临时收件箱复制一个独立地址,为本轮分配代号,例如 case-r17。同一轮内的首次发送与重发保留这个地址,并记录预发版本、账号代号、验证用途及会话代号。不要每点一次重发就换地址,那会把「同账号重发」变成「新账号首次发送」。
每个请求分别记下业务请求 ID、响应结果以及发送服务生成的事件 ID。业务接口返回成功可能只说明任务入队;若异步任务尚未创建发送事件,该格先记「待关联」,之后补齐。请求被限流或拒绝时,通常不应期待一封新邮件,仍以接口契约为准。
Tempcase 的邮件记录 ID 属于收件侧,不会天然等于业务请求 ID。若收件详情没有暴露邮件头或关联字段,需要通过发信日志、受控测试标记或测试环境的观测能力补足,不能凭时间接近强行配对。
建立五列关联表,让每封信有出处
下面五列是最小关联骨架。账号、环境、规则版本和时间轴放在本轮记录头部;一个请求触发多个投递尝试时,保留多行,并注明重试关系,不要覆盖旧事件。
| 测试轮次 | 请求 ID | 投递事件 ID | 邮件记录 ID | 业务校验结果 |
|---|---|---|---|---|
| case-r17 / R1 | req-a |
evt-a |
mail-a,后到 |
旧码 A:预期拒绝;实际接受 |
| case-r17 / R2 | req-b |
evt-b |
mail-b,先到 |
新码 B:在独立复现中校验 |
这里的「投递事件」还应注明阶段:入队、提交发信服务、远端接受或退信。它不是笼统的「已送达」。邮件记录 ID 可以作为定位线索,但不能替代业务验证接口的结果。
连续重发、双窗口、队列延迟,分别证明什么
连续重发:检查规则与限流
在允许的重发间隔外发送 R1、R2,分别记录响应;再单独测试冷却期内的点击。核对被拒绝的请求是否真的没有新任务,以及重发后有效期是否符合约定。不要靠高频请求制造压力,也不要绕过限流。
双窗口:检查状态作用域
在两个窗口使用同一测试账号,按明确顺序触发请求,记录各自会话代号。观察撤销规则是否跨窗口生效。一个窗口还显示旧提示,不等于服务端仍接受旧码;反过来,页面已更新也不能证明服务端完成了撤销。
队列延迟:检查乱序下的业务结果
只在获授权的测试环境,通过可控队列或故障注入延迟 R1,让 R2 先投递。记录注入位置和延迟范围。这组测试证明系统能否在乱序下遵守验证码规则,不证明真实网络的投递时延,也不应修改生产队列。
邮件顺序不等于请求顺序
请求顺序、签发顺序、任务执行顺序和接收顺序可能不同。邮件的 Date 头也由发送侧生成,不能直接当成收件时间。识别验证码乱序到达,应优先使用可追溯的事件关联,而非只看最新一封。
在自己控制的模板中,可放入不含秘密的测试关联代号,或在日志侧记录请求 ID 与邮件 Message-ID 的映射。验证码本身不能充当关联键:系统可能复用同一个码,不同请求也可能出现相同数字。没有关联证据时,结论应写「无法确认所属请求」。
旧码失效,要回业务端验证
把三件事分开断言:邮件是否进入收件箱;验证码是否被业务端接受;认证成功后是否建立了正确的会话或业务状态。收到邮件,不等于码有效;验证码接口返回成功,也不一定代表登录流程已经完成。
检查旧码时,在 R2 签发成功后提交 R1 对应的码,并记录业务错误类型与挑战状态。新码是否可用、成功后能否重复使用,建议用独立复现分支验证:先用新码成功可能消费整个挑战,使后续旧码失败,却掩盖了重发撤销没有生效的问题。
每个分支都要重新建立同样的初始条件,避免超过尝试次数。只记录「接受/拒绝」及稳定错误类别,不把完整验证码写进断言报告、截图名称或持续集成日志。
时间证据:统一格式,也保留来源
建议使用带时区的 ISO 8601,汇总时统一转为 UTC,同时保留原值与来源。例如「业务服务签发时间」「发信服务接受时间」「收件服务记录时间」「浏览器观察时间」应分开命名。显示格式相同,并不代表这些机器的时钟同步。
- 同一进程内测耗时,用单调时钟;同时留一个可对照的墙上时间。
- 跨服务比较先确认校时情况;没有可信偏差范围,不直接相减宣称精确延迟。
- 轮询首次发现邮件的时间只是观察时间。页面每隔数秒检查一次,会引入观察窗口。
- 邮件头时间只能作为旁证,不替代签发、入队或业务校验时间。
如果你只知道「某次检查没有,下一次检查出现」,就记录这个区间。对无法测准的部分诚实留白,比给出毫秒级但来源不明的结论更有用。
复现示例:第二封先到,第一封后到
下面是受控示例,不代表 Tempcase 或某个业务系统发生过该故障。预期规则是:同一挑战中,R2 新码签发成功后,R1 旧码立即失效。
- 建立测试挑战并发送 R1,记下
req-a → evt-a,在测试队列延迟其投递。 - 在允许重发后发送 R2,确认新码已签发,并记下
req-b → evt-b。 - 先观察到
mail-b,释放延迟后再观察到mail-a;用关联代号确认两封信的归属。 - 在未成功消费挑战的状态下提交旧码 A。若被接受,记录验证响应与挑战状态,立即结束本分支。
缺陷记录摘要 · 说明用示例
- 标题
- 同一挑战重发签发新码后,旧码仍可通过校验
- 预期
- R2 签发成功后,提交 R1 旧码应被拒绝。
- 实际
- 旧码 A 被接受;关联链与校验响应已脱敏留存。
- 边界
- 乱序是触发条件,不直接证明根因在队列;仍需核查撤销与校验逻辑。
如果只是第一封晚到,而旧码被正确拒绝,不应把「乱序」直接写成认证缺陷。它可能需要改进邮件提示或页面引导,但这与安全规则失效是两类问题。
交给同事的是脱敏证据,不是完整验证码
交接包需要让另一位同事按步骤复现,而不是让他使用你的凭证。可沿用下面的清单;账号用代号,真实地址和关联 ID 按团队数据分级处理。
一份最小可复现记录
- 环境与构建版本、规则版本、测试轮次及账号代号。
- 初始状态、会话作用域、请求间隔与延迟注入方式。
- 五列关联表、带来源的时间轴、脱敏后的响应类别。
- 预期与实际、复现次数、未覆盖的分支及已知不确定项。
完整验证码、登录 token、Cookie、认证链接以及临时邮箱访问 token 都不应出现在共享报告中。截图遮挡正文中的秘密,录屏检查地址栏和开发者工具。也不建议用普通哈希保存短数字验证码:取值空间太小,容易被枚举;使用 A、B 这样的无关代号即可。
何时换地址,何时保留同一账号
测试轮次结束、需要验证全新注册路径时,换一个地址有助于隔离残留邮件。仍在检查同一账号的重发、双窗口、限流或旧码撤销时,保留原地址与上下文,否则测试前提就变了。
Tempcase 临时地址默认 3 小时有效,可续期,单个地址最长 24 小时;台内续期每次请求追加 3 小时,并受上限约束。过期后无法恢复邮件,别把收件箱当作证据仓库。需要跨天保留账号收信入口,可用长期转发登录入口建立别名;别名只转发来信,不能代替业务日志或无限期证据留存。
下一轮:先把对应关系跑通
第一次实施时,不必同时覆盖所有异常。先跑一轮可关联的正常发送,再加一次重发,最后引入可控乱序。若连邮件是否发出都无法确认,先按验证码到达排查核对发送与接收证据;到信后要检查正文布局,再看邮件模板预览工作台。