Share
Embed
Transcript
27 slides
-
@acomagu 伊藤勇希 - 会津大学23期 - 東京からリモートでデザイニウム会津の仕事をさせていただいています - 武蔵村山市という超田舎に住んでいます -
今日は主に Stripe の話をしますが、5日後に JAWS-UG CDK 支部の CDK Conference Extra というイベントに「Terraform CDK in AWS CDK」というタイトルで 登壇しますので良かったら見に来てください Twitter: @acomagu -
テストでモック/スタブを利用するべきか? 外部サービスに依存するとき、それを実際に使う方法とモックする方法がある モック/スタブの利点 - まだ実装がない外部ライブラリ等があっても実装開始可能 - 外部を汚さずに実行可能 - 速い モック/スタブのデメリット
- 実際と違うコードが動く - 外部サービスの仕様に対して正確に模倣・追従することが必要 -
なぜ E2E テストがほとんどなのか - 1年ほど前まで自動テストが存在せず、そのときに最も課題だったのが「安心して コードを変更できない」ことだった - 開発の空き時間に E2E テストを徐々に導入していくことで、割と初期から「プロダク
ト全体の包括的な動作確認ができる」というメリットを得られた -
Stripe は E2E テストがものすごくやりやすい - Stripe は公式でローカルで動くモックサーバーが提供されていたりするが、「本物」 をそのままテストで利用する方法もかなり充実している - 通常外部サービスをそのままテストで使おうとすると、結構つらみが多い場合もあ
る - レスポンスが遅くてテストに時間がかかる - かといって並列化すると Rate Limit に引っかかる - たまに謎エラーが返却されてテストごと落ちる - 異常系を再現する方法がない ↑Stripe では今のところ全て経験していない - 唯一の Pain Point は(個人的には)Webhook だが、Stripe CLI の stripe listen –forward-to localhost でなんとかなりそう -
Samurai.MaaS では Webhook を利用していない - E2E テストが大変になる - Webhook を受け入れるコードにバグがあると、Stripe
との不整合が発生する可能 性があり、回復を手動で行うしかない - 例えば「稀に Webhook リクエストを無視してしまうバグ」が存在したら? →回復には Stripe と DB を全件チェックして突き合わせる処理を行う必要があるかも 上記の理由から、Samurai.MaaS では Webhook を利用しない構成にしています。 (昔は Stripe Webhook を全面的に活用し Event Sourcing を行っていましたが、上記のような理由で辞めてしま いました 歴史: SpeakerDeck「JP_Stripes 一貫性に寄与する設計」) 代わりに導入したのが→リコンサイル -
リコンサイル(突合処理)とは? 自前 DB の「購入」と Stripe 上の「購入」を一件一件照らし合わせ、不整合が無いか確 認するバッチ処理 不整合があれば: 整合性が取れるようにどちらかを合わせる (詳しくは:
SpeakerDeck「Stripe リコンサイルの勘所」) -
私達の実装 Purchase というオブジェクトが Stripe の Checkout Session の状態に依存する状態を 持っています。 私達のサービスでは、Stripe
は下記の6つの状態を想定すれば十分であることが分か りました。 「Checkout Session オープン」 「Checkout Session 期限切れ」 「キャンセル済み(全額返金済み or 失敗)」 「キャプチャ待ち」 「一部キャプチャ待ち」 「成功」 まず Stripe の支払いデータが上記のいずれに当たるのか返却する関数を作成しまし た。 「Stripe リコンサイルの勘所」p26 より -
Samurai.MaaS のリコンサイル 私達のリコンサイルは Stripe 側は - Checkout Session オープン -
Checkout Session 期限切れ - キャンセル済み(全額返金済み or 失敗) - 未キャプチャ - 一部未キャプチャ - 成功 の6つの状態のうちのいずれかとして捉えています。 -
Samurai.MaaS のリコンサイル Samurai.MaaS 側の “Purchase” は、 - Incompleted - Unapproved
- Uncaptured - Captured - Refunded - Denied の6つの状態があります。 -
- Incompleted - Unapproved - Uncaptured - Captured - Refunded
- Denied - Checkout Session オープン - Checkout Session 期限切れ - キャンセル済み(全額返金済み or 失敗) - 未キャプチャ - 一部未キャプチャ - 成功 Samurai.MaaS 側 Stripe 側 -
- Incompleted - Unapproved - Uncaptured - Captured - Refunded
- Denied - Checkout Session オープン - Checkout Session 期限切れ - キャンセル済み(全額返金済み or 失敗) - 未キャプチャ - 一部未キャプチャ - 成功 正しい状態 Samurai.MaaS 側 Stripe 側 -
- Incompleted - Unapproved - Uncaptured - Captured - Refunded
- Denied - Checkout Session オープン - Checkout Session 期限切れ - キャンセル済み(全額返金済み or 失敗) - 未キャプチャ - 一部未キャプチャ - 成功 正しい状態 - (Deleted) Samurai.MaaS 側 Stripe 側 -
- Incompleted - Unapproved - Uncaptured - Captured - Refunded
- Denied - Checkout Session オープン - Checkout Session 期限切れ - キャンセル済み(全額返金済み or 失敗) - 未キャプチャ - 一部未キャプチャ - 成功 正しい状態 - (Deleted) ↑こちらを「正しくない状態」へと 意図的にずらせればいい (どうやって?) Samurai.MaaS 側 Stripe 側 -
ずらし方 Stripe API /checkout/sessions/expire で可能 - Checkout Session オープン -
Checkout Session 期限切れ -
ずらし方 Stripe API /payment_pages/{checkout_session_id}/confirm を User-Agent: Stripe/v1 stripe-cli/master 等のヘッダをつけて叩くと可能 -
Checkout Session オープン - 未キャプチャ(もしくは成功) -
ずらし方 Stripe API /payment_pages/{checkout_session_id}/confirm に Stripe のエラーテストカードトークン(tok_visa_chargeDeclined 等)を投げると可能 - Checkout
Session オープン - キャンセル済み(全額返金済み or 失敗) -
Stripe API を叩けば状態を意図的にずらせる よってリコンサイルのテストは - Samurai.MaaS 側でテストしたい状態(Incomplete, Captured, …)まで購入を進める -
Stripe API を叩いて購入に紐づいた Payment Intent 等の状態を「ずらす」 - リコンサイルを実行し、差分が意図する形で解消されていることを確認 という手順で行っています。 -
金額をずらす場合は? これらの状態のとき金額がずれている場合についてもテストしたいが、Stripe API からは無理 そう... ↓ 一部は Samurai.MaaS 側のデータの方をずらすことで再現 -
Checkout Session オープン - 未キャプチャ - 一部未キャプチャ - 成功 -
まとめ - Samurai.MaaS では、リコンサイル時に「Stripe の状態」を必要な情報のみ含むよう に、6つの状態に単純化してからリコンサイルを行っている - なので、リコンサイルのテストでは、その6つの状態を他の状態にずらすことでリコン サイルが必要な状況を再現する -
これは、Stripe API で全て行えることが分かった - 金額をずらすことに関しては、Stripe API からはほとんど再現できないので、こちら 側のデータを変更して再現している -
おまけ: Stripe と E2E テストの Tips ① Stripe サンドボックスを活用しよう
普通に開発環境と同じ要領で E2E テストを回してしまうと、テストが回るたびに大量の Payment Intent や Customer が作成されてしまう そこで Stripe サンドボックス! Stripe サンドボックスは、「メインの環境の設定をコピーして作成されるテスト専用環境」 普通に別アカウントを作成するのと違い、 - Price や設定がコピーされる - 改めてチームメンバーを招待する必要がない というメリットがあり便利です。 -
おまけ: Stripe と E2E テストの Tips ② Test Clocks を活用しよう
「サブスクリプションが切れた時」の動作をするためには、サブスクリプションが切れるま で1ヶ月待たなければいけない? そこで Test Clocks! Customer を作成するときに Test Clocks を指定して作成すれば、その Customer の時 間だけ自由に進めることができる。 (サブスクリプション限定機能)