こんにちは竹田です。
今回は弊社サービスの採用係長の決済関連コードを自動テストに落とし込めた話です。大変だった点、良かった点、まだ解決できていない問題点を書いていこうと思います。
目次
大変だった点
決済方法が3つあって大変
採用係長では決済システムを3つ採用しています。「クレジットカード、請求書払い、銀行振り込み」の3つそれぞれで料金計算のロジックが分かれており、それぞれに対応するテストコードを書く必要がありました。単純に物量が多く大変だった点の1つです。
過去のユニットテストがメンテナンスされていない
料金計算ロジックはPHPで書かれており、テストフレームワークはPHPUnitを使用しています。
それぞれの決済方法が作られた当初に書かれているテストコードはありました。しかし、それらのテストコードを調査すると「既に失敗しているテスト」「何のテストなのか読み取れないテスト」「昔のマスターデータが前提のテスト」が混在していました。これらのテストケースはメンテナンスのしようがないため今回思い切って捨てることにしました。
時間の制約があるため今回捨てた小さいユニットテストケースは改めて作らず、フロントエンドからの入力値を基に、いくつかの関数の処理を経た、最終の値だけをテストするというようなテストコードを作ることにしました。
今回小さいユニットテストを削ることになりましたが、最終の値を確認するので動作を一気通貫して動かすテストができるようになったメリットはありました。
バックエンドが分かれている
採用係長ではバックエンドの処理がNode.jsとPHPで分かれており、フロントエンドからの入力値をNode.jsで処理してDBに挿入し、PHPでそのDBの値を基に日々の売り上げを計算するという処理を行っています。
この仕様のためにPHPのみでテストを完結させることが難しく、Node.jsの処理を模した関数を新たにPHP側で実装するという手間が発生してしまいました。(今後改善予定)
特定部分に絞ったテストを書くことが困難
ユニットテストがメンテされていない問題にも関わるのですが、そもそも小さな機能のテストをしようとすると、そのテストができるデータの状態を作るという工程が複雑なことが多く、テストコードが肥大化しがちでした。
良かった点
手動で行うテストの工数が減った
テストコードを書く以前は料金がDBに正しく反映されていることを一回確かめるために、ローカルで立ち上げた採用係長のフロントエンドから有料プラン登録を手作業で行い、さらに手作業でバッチを動かして、DBの中身を確認してスプレッドシートに結果のスクショを貼って・・・のような地獄の作業が発生していました!
今回相当パターン数のテストケースを作成したため、テストがオールグリーンになっていれば動作を担保できるようになりました。複数パターンのテストケースが必要な場合でも、少なくとも全てのテストケースをテストコードに追加すれば、手動テストはそのテストコードに落とし込んだうちの1パターンだけ確認する、というような手段を選びやすくなりました。
追加効果としてストレスの軽減度合いが大きいです。
リファクタリングを行いやすくなった
今回小さいユニットテストケースは作ることができませんでしたが、最終の出力値だけは少なくとも担保されるようになったため、処理途中の関数のリファクタリングを自信を持ってできるようになりました。既存のコードでカオスな部分を把握しているのに手を出せないという事が無くなりつつあります。
既存のコードに影響確認が容易になった
今までは料金計算ロジックのバグ修正等を行った後に、既存の処理に影響が出ていないかのテストを手動で複数パターン実施していました。しかし今回のテストコード追加により、自動テストが失敗しないかどうかで既存のコードへの影響が出ていない事の確認ができるようになり、バグ修正も容易になりました。
モックの使い方を知ることができた
クレジットカード、請求書払いの決済処理は外部機能との連携になります。テストコード上で外部機能に毎回リクエストを投げる訳にはいかず、モックを作成する必要がありました。幸いなことに過去にクレジットカードと請求書払いの外部連携機能のモックが作成されていました。今まで外部連携する時のモックをどういう作りにすると良いのか分からなかったので勉強になりました。
既存のテストコードのコピペで新たなパターンがすぐに作成できる
今回新規ユーザー登録や、有料プラン登録の実際の動作を模した関数が作成できました。
それにより「このテストパターンつくりたいな」となった時に、既存のテストケースを丸々持ってきて引数を変えるだけで、新しいテストケースがすぐ出来上がるようになりました。
問題点
Node.jsの処理を模した関数を新たに作成しているため、Node.js側で変更があると実装と差分が出てきてしまう
バックエンドはNode.jsとPHPに処理が分かれており、今回Node.js側での処理を模倣した関数をPHP側で新規作成しました。
もしNode.js側に追加修正が入った場合、PHPの模倣関数とNode.jsの実体が乖離してしまいます。この状態を放っておくとテストコードが陳腐化してしまいます。
そのため解決策として2つ考えています。テストコード中でPHP側からNode.js(GraphQL)のクエリを実際に叩くようにして実体と乖離が絶対に起きないようにする。又はPHPの模倣関数とNode.js側の実体の関数に乖離が出ていないかを確認するテストコードを新たに追加する。ことで対処しようと考えています。
GraphQLのクエリを全てのテストで叩くようにするのはテストの実行時間が長くなる可能性があるので、今後調査して、どちらの手段を取るか決めようと思っています。
終わりに
最近テストコードを書くことが多くなっており、テストを書く前提のコードを作ることができるようになりました。テスト駆動開発に近いような手法に慣れてきたように感じます。
テストを書いておくと何をするべきか明確になりますし、後で修正する時も何度も手動で確認するというような作業が短縮できて精神衛生的にもプラスになる事が多いです。
大きなプログラムにテスト書いていくのは最初ハードルが高かったのですが、一度作れてしまうと必ずその作業はペイできると思っています。何か大きい改修が入るついでに全体のテストを作って見るのはどうでしょうか?
ありがとうございました。