$30 off During Our Annual Pro Sale. View Details »

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

meijin
November 25, 2020

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

meijin

November 25, 2020
Tweet

More Decks by meijin

Other Decks in Technology

Transcript

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

    View Slide

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

    View Slide

  3. 自己紹介
    3

    View Slide

  4. 自己紹介
    - twitter:   @meijin_garden
    - career: 奈良高専 → LIFULL → NoSchool CTO
    - skill: Laravel/Nuxt.ts/Next.js/Nest.JS/AWS(Fargate)/Firebase
    4

    View Slide

  5. オンライン家庭教師マナリンクを開発しています
    5
    オンライン家庭教師の CtoCマッチング。
    単発課金の指導コースと
    月額課金の指導コースがあり、
    ご家庭ユーザーがクレカで決済する。

    View Slide

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

    View Slide

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

    View Slide

  8. 月額決済機能のシーケンス図(※一部割愛)
    8
    ● とにかく実行手順が多い
    ○ 決済種別の判定→認可判定→決済処理
    →支払いステータス更新・先生の売上データ更新
    →メール等の通知
    ● ローカルでテストするのが面倒
    ○ いちいちNuxtを起動してテスト用のクレカを入力するのか?
    ○ 月額課金の2ヶ月目以降の動作テストが無理

    View Slide

  9. テストコードの作成方針
    9

    View Slide

  10. 入出力の結合テストだけでも書く
    - APIを叩く結合テストだけは絶対に書く
    - 入力
    - 決済エンドポイントにトークン等のPOST
    - 出力
    - DBへの保存、Pay.jpへの通信、メール等の通知実行
    - 単体テストは必要に応じて
    - 結合テストさえあればリファクタや改修に取り組める
    10

    View Slide

  11. Pay.jp SDKのラッパー実装を
    やってみた
    11

    View Slide

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

    View Slide

  13. Pay.jpラッパーを作ると嬉しいこと
    13
    - (前提)Pay.jpのAPIは公式SDK経由で実行する
    - https://github.com/payjp/payjp-php
    - ラッパーによってSDKへの依存度が下がる
    - コードから直接Pay.jp SDKを実行すると依存度が強くなる
    - SDKの仕様変更の影響範囲がテストコードも含め増えてしまう
    - ラッパーへのin/outは内製のValueObjectにする

    View Slide

  14. ラッパーを利用するときはInjectionする
    14
    Dependency Injectionすることで、
    テスト時にモックに差し替えが可能になる。

    View Slide

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

    View Slide

  16. 所感①
    - [KEEP]実際の決済処理を実行せずにテストできる
    - 開発が高速
    - Pay.jpのテスト環境を汚さない
    - リファクタが捗る(リリース後、改修のたびにリファクタをしている)
    - [PROBLEM]Mock化のコードなどが職人芸になりがち
    - 職人芸をまとめたオリジナルの基底TestCaseクラスを作ったり
    READMEを書いたりして職人芸の緩和に務める
    16

    View Slide

  17. 所感②
    - [TRY]interfaceにして、app->bind()で差し替える
    - class PayjpCharge implements ChargeInterface
    - app->bind(ChargeInterface::class, MockChargeInterface::class)
    - Mockery::mock('alias:(以下略)’)の書き方よりは慣れ親しんでいる
    &型安全
    - 決済以外の処理は基本的にInterfaceに寄せているので合わせていきたい
    - 必ずErrorをthrowする実装クラスでTransactionのテストもできる
    17

    View Slide

  18. その他試行錯誤していること
    18

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  22. 例:サブスク更新時のEventを返す関数
    22
    テスト用のサブスクIDなどを受け取って、
    Payjp\Event型の課金Eventを返すファクトリ。
    テスト時はEventオブジェクトをモック化して
    テストデータのIDで更新処理をテストできる!

    View Slide

  23. GitHub Actionsの設定
    23

    View Slide

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

    View Slide

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

    View Slide

  26. 最後に告知
    26

    View Slide

  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

    View Slide

  28. ご清聴ありがとうございました
    28

    View Slide