Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PHPUnitで単発/月額決済ありサービスを自動テストしている話

7fccfb690a818ed2f3a15fc21d426d5a?s=47 meijin
November 25, 2020

 PHPUnitで単発/月額決済ありサービスを自動テストしている話

7fccfb690a818ed2f3a15fc21d426d5a?s=128

meijin

November 25, 2020
Tweet

Transcript

  1. PHPUnitで 単発/月額決済ありサービスを 自動テストしている話 株式会社NoSchool CTO / meijin

  2. 目次 - 自己紹介 - Pay.jpを用いた決済の仕組みと月額決済の苦悩 - PHPUnitを用いたPay.jp SDK実行のテストコード記述 - 告知

    2
  3. 自己紹介 3

  4. 自己紹介 - twitter:   @meijin_garden - career: 奈良高専 → LIFULL

    → NoSchool CTO - skill: Laravel/Nuxt.ts/Next.js/Nest.JS/AWS(Fargate)/Firebase 4
  5. オンライン家庭教師マナリンクを開発しています 5 オンライン家庭教師の CtoCマッチング。 単発課金の指導コースと 月額課金の指導コースがあり、 ご家庭ユーザーがクレカで決済する。

  6. Pay.jpを用いた決済の仕組み 6

  7. 月額決済機能のシーケンス図(※一部割愛) 7

  8. 月額決済機能のシーケンス図(※一部割愛) 8 • とにかく実行手順が多い ◦ 決済種別の判定→認可判定→決済処理 →支払いステータス更新・先生の売上データ更新 →メール等の通知 • ローカルでテストするのが面倒

    ◦ いちいちNuxtを起動してテスト用のクレカを入力するのか? ◦ 月額課金の2ヶ月目以降の動作テストが無理
  9. テストコードの作成方針 9

  10. 入出力の結合テストだけでも書く - APIを叩く結合テストだけは絶対に書く - 入力 - 決済エンドポイントにトークン等のPOST - 出力 -

    DBへの保存、Pay.jpへの通信、メール等の通知実行 - 単体テストは必要に応じて - 結合テストさえあればリファクタや改修に取り組める 10
  11. Pay.jp SDKのラッパー実装を やってみた 11

  12. Pay.jp SDKを呼び出すだけのラッパーを内製する 12 Charge::createがPay.jp SDKの処理。 これを単に呼び出すだけのクラスを作る。

  13. Pay.jpラッパーを作ると嬉しいこと 13 - (前提)Pay.jpのAPIは公式SDK経由で実行する - https://github.com/payjp/payjp-php - ラッパーによってSDKへの依存度が下がる - コードから直接Pay.jp

    SDKを実行すると依存度が強くなる - SDKの仕様変更の影響範囲がテストコードも含め増えてしまう - ラッパーへのin/outは内製のValueObjectにする
  14. ラッパーを利用するときはInjectionする 14 Dependency Injectionすることで、 テスト時にモックに差し替えが可能になる。

  15. テストコードでモックに差し替え 15 app->instance()メソッドにより モックをコードに注入できる。

  16. 所感① - [KEEP]実際の決済処理を実行せずにテストできる - 開発が高速 - Pay.jpのテスト環境を汚さない - リファクタが捗る(リリース後、改修のたびにリファクタをしている) -

    [PROBLEM]Mock化のコードなどが職人芸になりがち - 職人芸をまとめたオリジナルの基底TestCaseクラスを作ったり READMEを書いたりして職人芸の緩和に務める 16
  17. 所感② - [TRY]interfaceにして、app->bind()で差し替える - class PayjpCharge implements ChargeInterface - app->bind(ChargeInterface::class,

    MockChargeInterface::class) - Mockery::mock('alias:(以下略)’)の書き方よりは慣れ親しんでいる &型安全 - 決済以外の処理は基本的にInterfaceに寄せているので合わせていきたい - 必ずErrorをthrowする実装クラスでTransactionのテストもできる 17
  18. その他試行錯誤していること 18

  19. 複数のPay.jpラッパーをまとめるAdaptorの開発 19 一度に複数のラッパーを実行するので、 【定期課金の実行】といった責務で まとめたAdaptor/Interfaceを作り、 色々なサブスク機能で再利用可能にする

  20. サブスク更新時のテスト 20

  21. POSTされるデータのFixtureを作る - Pay.jpから、課金後1ヶ月毎に 登録したCallback Endpointに課金EventがPOSTされる仕様 - このタイミングで先生の売上更新があるのでめっちゃ重要 - Eventの中にサブスクIDとか金額が含まれている -

    それで該当のサブスクの検索とか売上更新処理をやる - このEventのFixtureを作る 21
  22. 例:サブスク更新時のEventを返す関数 22 テスト用のサブスクIDなどを受け取って、 Payjp\Event型の課金Eventを返すファクトリ。 テスト時はEventオブジェクトをモック化して テストデータのIDで更新処理をテストできる!

  23. GitHub Actionsの設定 23

  24. GitHub Actionsの設定 24 kirschbaumdevelopment/laravel-test-runner:7.4 を使わせてもらっています

  25. 自動テストを導入した所感 - [KEEP]リファクタリングの障壁が下がる - [KEEP]ドメイン知識の薄い業務委託のエンジニアさんにも 決済処理に関わってもらいやすい≒リスクが小さい - [PROBLEM]GitHub Actionsは実行時間で課金なので、 いずれは実行時間を短縮する工夫が要るかも。

    25
  26. 最後に告知 26

  27. Webエンジニア採用中!(副業でお試し勤務OK) - Nuxt.js/Next.js/NestJS/Laravel/AWS(Fargate)/Firebase/Pay.jp - テストコード(PHPUnit/jest)×GitHub Actions×Dockerデプロイ - 現在フルタイム3名(内開発1名...寂しい)、ご家庭・先生方の双方のニーズや課題 をヒアリングしつつ売上を立てていく日々 -

    ベンチャーなのでもちろんSOも検討します オンライン家庭教師という新しい生き方を広めつつ、 既存の学習市場のニーズを満たしていく事業の話を聞きたい方、お声がけください! 27 名人さん | マナリンクCTO https://twitter.com/Meijin_garden
  28. ご清聴ありがとうございました 28