SODA Engineering Blog
©️

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 Engineering Blog
SODA Engineering Blog

Discussion