你的CI流水线凌晨2点崩过吗?不是因为代码,是因为两个测试任务同时抢了一封验证码邮件。
这是Selenium(浏览器自动化测试框架)开发者的经典噩梦:你能自动化登录、表单、支付、导航,但邮箱验证这一步,90%的团队还在靠人肉。要么跳过,要么Mock(模拟数据),要么共享一个Gmail账号——然后看着测试在并行运行时互相串台。
一位折腾了多年这个问题的开发者最近开源了他的解法。不是更复杂的IMAP协议抓取,不是维护成本爆炸的正则表达式,而是一个简单的三步骤:每个测试独享一个收件箱,API直接吐验证码,全程无浏览器操作。
为什么共享邮箱是定时炸弹
他试过所有你能搜到的方案。共享Gmail账号看起来最省事,直到两个并行测试同时提交注册表单,A测试读到了B的OTP(一次性密码)。这种竞态条件(Race Condition)产生的Flaky Test(不稳定测试)根本没法调试——日志显示一切正常,结果就是随机失败。
硬编码临时邮箱网站更糟。你需要再开一个Selenium会话去爬它的网页UI,DOM结构一变就挂,网站宕机时整个CI跟着陪葬。Mock邮件步骤是最隐蔽的毒药:测试全绿,生产环境的真实邮件管道却默默坏了,等你发现时用户已经收不到验证码。
他甚至试过nodemailer+IMAP(邮件访问协议)。OAuth配置复杂到怀疑人生,Token还要定期轮换,最后还得写正则从邮件正文里抠OTP——"维护这套东西的时间,够我手动点几百封邮件了。"
真正需要的其实就三样东西:每次测试一个全新的收件箱、秒级送达、不用维护正则的OTP提取。
FreeCustom.Email的玩法
这个API的设计思路很产品经理:把邮件验证抽象成纯数据接口,彻底干掉浏览器环节。
安装CLI(命令行工具)只需要一行:
curl -fsSL freecustom.email/install.sh | sh
fce login
浏览器弹窗登录后,密钥自动写入系统钥匙串。支持Homebrew、npm、Chocolatey、Scoop、Go Install,覆盖主流开发环境。
Python测试的依赖也极简:
pip install freecustom-email selenium pytest pytest-asyncio
核心模式就三步:创建一次性收件箱 → 填入注册表单 → API轮询取OTP。每个测试隔离,并行运行永不撞车。
生产级pytest配置长什么样
他放出了正在CI里跑的fixture代码。关键设计是异步轮询:提交表单后,用get_otp()方法以1秒间隔查10次,超时就抛异常。这比固定time.sleep()快得多,失败时也明确知道是邮件没收到还是OTP提取失败。
收件箱生命周期绑定测试作用域。pytest的fixture机制保证:测试结束,收件箱自动清理。不会堆积垃圾数据,不会泄露测试之间的状态。
代码里还藏了个细节:OTP提取支持多种格式。6位数字验证码、带横杠的激活链接、甚至自定义正则——但默认配置已经覆盖99%的场景,不需要你动手调。
这个方案的真正价值
它把"邮件验证"从E2E测试(端到端测试)的灰色地带,变成了可信赖的自动化环节。不再是"这里我们Mock一下"或者"这里需要人工介入",而是和点击按钮、填写表单一样,交给机器稳定执行。
代价是引入了一个外部服务依赖。但比起维护IMAP连接池、处理Google的OAuth策略变动、或者调试临时邮箱网站的反爬机制,这个 trade-off(权衡)对大多数团队来说是正向的。
GitHub仓库里有个Issue很有意思:有人问能不能自建服务端,作者回复说核心协议其实简单,但"我建议你先试试托管版,把省下来的时间拿去写真正的业务测试"。
你的团队现在怎么处理邮箱验证?还在用共享测试账号,还是已经找到了更干净的解法?
热门跟贴