©️
APIを安全にリプレイスするために統合テストの副作用を真面目にチェックする
APIを安全にフルリプレイスするためには?
結論:リプレイス前後のAPIを外から呼び出し、入出力と副作用について挙動が変わらないことを確認する
技術的負債返済のためにAPIをリプレイスすることが多々あるが、危険なのはリプレイス後のAPIに特化したテストしか書かないことである。それでは仕様の見落としなどにより挙動の変更を入れ込んでしまうリスクが高まる。リプレイス前後の両方のAPIに共通で使えるテストを充実させたい。そうするとAPIを外から呼び出すような統合テストが欲しくなる。
どうやって副作用を確認するのか?
入出力のテストはどんなツールでも難なく行えるはずだが、副作用についてはアーキテクチャ次第となる。
DB, Redis, Memcachedなどのデータストアへの書き込み
格納されたデータをGETして確認する
ジョブキューへのイベント発行
キューからイベントを取り出して確認する
- 弊社の統合テストではイベントはキューに格納されるが取り出されることがないという仕組みになっているので上記で確認
- もし統合テストでキューからイベントを取り出してジョブを実行するアーキテクチャとなっているなら、そのジョブによる副作用まで追って確認
外部API呼び出し
対応するGET APIを呼び出して確認する等
考察: それぞれ難しい場合はどうする?
- どうにも外からのテストで副作用をチェックするのが難しいと判断したら、そこはより内側のテストであったり、モックライブラリを使ったりなどして重点的にテストするのが良さそうである。
- supertestやkarateのような外形テスト用の薄いFWを使うのでは、この記事のように細かくテストするのは難しいのかもしれない。もし大規模なリプレイス計画があるなら、そういったものではなく、改めてプロジェクトの中で統合テストを作る方針とするも手である。
[補足資料] 弊社のAPI呼び出しのテストについて
特殊なので補足資料として別途考察してみる。
外部APIの多くはモックしているもののライブラリは使っておらず、自作のモッククライアントをAPIごとに作っている。そのモッククライアントに呼び出し履歴機能を実装することで実現可能だと思っている(実績はない)。グローバル変数として定義したりデータストアに定義したりして、APIとテストの両方から参照できるようにするイメージである。
実装例
package foo_api
var Count = 0 // 呼び出し回数を記録
func NewMockClient() FooAPIClient {
roundTrip := func(r *http.Request) (*http.Response, error) {
switch r.URL.Path {
case "/login":
Count++
...
}
}
}

株式会社SODAの開発組織がお届けするZenn Publicationです。 是非Entrance Bookもご覧ください! → recruit.soda-inc.jp/engineer
Discussion