披露:本文包含联盟链接。如您通过链接购买,我们可能获得佣金,且您无需承担额外费用。
测试结账流程,意味着要模拟用户点击“支付”到后端确认“资金到账”之间发生的一切——拒付、风控检查、退款、乱序触发的 Webhook——而全程不能真正扣款。支付处理商发布沙盒环境和公开的测试卡号,正是为此而生。本指南介绍 Stripe、PayPal、Braintree、Adyen 和 Square 提供的测试卡与沙盒工具,以及如何将它们与虚拟账单数据结合使用的工作流。
“测试卡”到底是什么
测试卡是支付处理商在沙盒中保留的一个 16 位 PAN(主账号)。这个卡号能通过 Luhn 校验,看起来像真实的 Visa 或 Mastercard,并会触发特定的处理商响应——成功、拒付、余额不足、过期等——而永远不会路由到真实发卡行。多数处理商会在文档中发布一组公开的测试卡;请使用这些卡号而不是自己编造,因为末四位通常被编码为特定的拒付原因码。
Stripe——最完整的沙盒
Stripe 是测试基础设施的黄金标准。其沙盒(“测试模式”)接受以 pk_test_ 和 sk_test_ 开头的可发布密钥和秘密测试密钥,因此每个 API 调用都有测试对应版本,每个 Webhook 都可以通过 Stripe CLI 镜像到本地。
必备 Stripe 测试卡
| 卡号 | 品牌 | 结果 |
|---|---|---|
| 4242 4242 4242 4242 | Visa | 支付成功 |
| 4000 0027 6000 3184 | Visa | 拒付——附带欺诈拦截标记 |
| 4000 0000 0000 0002 | Visa | 通用拒付 |
| 4000 0000 0000 9995 | Visa | 余额不足 |
| 4000 0000 0000 0069 | Visa | 卡片过期 |
| 4000 0082 6000 3178 | Visa | 需要 3DS 验证 |
| 5555 5555 5555 4444 | Mastercard | 支付成功 |
| 3782 822463 10005 | Amex | 支付成功(Amex 测试卡,15 位) |
Stripe CLI:在本地重放 Webhook
杀手级功能是 Stripe CLI,它能把测试模式的实时事件转发到你本地的 Webhook 端点:
stripe login
stripe listen --forward-to http://localhost:8080/webhooks/stripe
这一条命令,就是“我测试了顺利路径”和“我测试了完整的顺利路径——包括那条更新我数据库的 Webhook”之间的区别。还可以手动触发特定事件:
stripe trigger payment_intent.succeeded
stripe trigger invoice.payment_failed
stripe trigger charge.refunded
PayPal——沙盒账户与虚拟卡
PayPal 提供了一个“沙盒”环境,你可以在开发者控制台创建独立的沙盒买家账户和商户账户。至少创建一个沙盒企业账户(商户)和一个个人账户(买家)。
沙盒测试卡——在 PayPal 沙盒内用于游客结账——包括以下公开卡号:
- Visa:4032035728984848(有效期填任意未来日期,CVV 123)
- Mastercard:5425233430109242
- Amex:374245455400126
这些卡仅在 PayPal 沙盒内有效;在其他任何地方使用都会得到通用拒付。PayPal 沙盒不像 Stripe 那样支持丰富的拒付场景——要测试 PayPal 拒付,请使用开发者控制台中的 reviewer 工具,给你的沙盒账户附加一个“负面测试”标记,强制下一笔交易失败。
Braintree——沙盒卡
Braintree(PayPal 旗下公司)在初始化时区分沙盒密钥与生产密钥,并发布了一套按特定响应码划分的测试卡:
| 卡号 | 结果 |
|---|---|
| 4111 1111 1111 1111 | 批准 |
| 5105 1051 0510 5100 | 批准(Mastercard) |
| 4000 1111 1111 1115 | 处理商拒付——卡类型未启用 |
| 5000 1111 1111 1114 | 处理商拒付——被发卡行拒付 |
| 4000 1111 1111 1112 | 处理商拒付——已拦截 |
Braintree 还允许你通过设置特定的街道地址或 CVV 值来控制 AVS 和 CVV 响应——这在测试高级风控和卡片验证路径时非常有用。
Adyen 和 Square
Adyen 提供测试账户,每个卡号都有可预测的结果,拒付原因码也非常出色。常用测试卡包括 4111 1111 1111 1111(Visa,已授权)和 5101 1800 0000 0007(Mastercard)。Adyen 响应对象上的“test”前缀让审计工作变得简单。
Square 发布了沙盒卡,如 4111 1111 1111 1111(Visa 扣款成功)和 5105 1051 0510 5100(Mastercard 拒付)。Square 沙盒允许你创建沙盒客户并将卡片存档。
最佳实践:测试每一条拒付路径
下面这份清单覆盖了大多数团队容易遗忘的失败面:
- 使用有效卡片成功扣款
- 通用处理商拒付
- 余额不足
- 卡片过期
- 需要 3DS 的场景(验证挑战弹窗出现且挑战完成成功;验证与取消——每条路径都重要)
- 卡片存档后,通过已保存的令牌稍后扣款
- 全额退款与部分退款
- 对已被拒付(争议)的扣款发起退款(追回路径)
- Webhook 到达两次——验证你的处理器是幂等的
- Webhook 在数据库写入之前到达(Stripe 称之为“事件 ID 领先于状态”的罕见乱序情况)
幂等的 Webhook 处理器是底线,不容妥协。使用事件 ID 作为你的幂等键。如果你发现自己在处理器里写出
if (!exists) { insert } else { skip }——恭喜你,你已经写出了幂等性。下次重构时千万别把它弄丢了。
将测试卡与虚拟账单数据配对使用
一次成功的沙盒扣款还依赖于 AVS(地址验证系统)——发卡行会核对邮编和街道号是否与卡片档案一致。大多数沙盒卡的测试环境会忽略 AVS 结果,但要测试你表单的错误路径(例如邮编错误触发错误提示),你需要稳定但明显虚构的账单数据。
这正是 USA Data Tools 地址生成器的用武之地:
curl "https://vic999.com/us-address/api/v1/address?count=20" \
-H "Authorization: Bearer YOUR_API_KEY" \
-o fixtures/billing-addresses.json
- 真实的地址让你能断言表单接受每一种邮编到州的组合。
- 按州生成的数据对测试扣款前的销售税明细行无价。
- 免税州生成器让你能验证特拉华、蒙大拿、新罕布什尔和俄勒冈的零税结账。
把生成的账单地址、Stripe 的需要 3DS 测试卡和一个生成的购买金额组合起来,你就得到了一个完全可复现的结账测试场景,一次性覆盖 AVS、税费和 3DS。
幂等性——悄无声息的结账杀手
真实世界的支付事故往往长这样:用户点击支付,请求在第 28 秒超时,用户再次点击支付——然后被扣了两次款。每个支付 API 都支持幂等键;请务必使用:
// Stripe 示例:传入幂等键
const paymentIntent = await stripe.paymentIntents.create({
amount: 1999,
currency: "usd",
customer: customerId,
}, {
idempotencyKey: `order_${orderId}_pay`,
});
同一客户端的重复调用(或恐慌用户连点 50 次)只会产生一次扣款。构建一个端到端测试:重复发送支付请求,断言只存在一笔扣款;这一个测试就能预防约 30% 的真实生产支付事故。
Webhook 重放:抓住罕见但致命的 Bug
Stripe 允许你在控制台重放任意 Webhook。保存 payment_intent.id,12 小时后点击“Resend”,验证你的处理器是否处理得当——很多真实 Bug 只在这种场景下才会浮现。结合生成的订单 ID 和地址,你就拥有了一个完全可复现的夹具,能精确触发你想要的路径。
CI 集成
使用独立的沙盒密钥,把你的拒付矩阵接入每晚运行的 CI:
- name: Checkout decline matrix
run: npx playwright test checkout-declines
env:
STRIPE_SECRET_KEY: ${{ secrets.STRIPE_TEST_SECRET_KEY }}
STRIPE_PUBLISHABLE_KEY: ${{ secrets.STRIPE_TEST_PUBLISHABLE_KEY }}
BILLING_FIXTURES_URL: https://vic999.com/us-address/api/v1/address?count=50
矩阵全绿的那个夜晚,就是可以发布的夜晚。
在支付场景中使用测试数据生成器
总结
测试支付流程并不复杂——但需要全面。处理商的沙盒覆盖了扣款侧;生成的虚拟数据覆盖了表单与 AVS 侧;幂等键模式加上重放驱动的 Webhook 测试,则覆盖了那些最终会演变成 3 万美元退款的隐性失败。先写出上面的拒付矩阵,用 Stripe CLI 接入本地 Webhook,再用地址生成器生成虚拟账单记录。矩阵全绿的第一晚,你的结账流程就不再是黑盒。