広範囲の変更にスナップショットテストで対応する

ライクル事業本部の石崎です。

先日、使用している外部のAPIに破壊的な変更が加えられました。 古いシステムは依存関係を意識できておらず、APIの変更の影響をコードの各所に受けてしまいました。

アップデートを安全に行うためにスナップショットテストを使って進めたので、その話をしていきたいと思います。

広範囲に影響を受ける

具体的に今回の依存関係が意識できていない状況とは、APIのモデルがデータアクセス層に閉じておらず、ユースケース部分にまで漏れている状態です。 またDBのデータアクセス関数の引数にまでAPIモデルが使われており、そこら中がAPIに依存してしまっています。
そのためAPIモデルを変更をしても挙動が変わらないことを担保するには、APIのデータアクセス部分のテストだけでは完結せず、ユースケースやDBのデータアクセスも巻き込んだテストを行う必要がありました。

気持ちとしてはアーキテクチャの改善をしたいところですが、あまりにも大規模な改修になるため、改修は行わない方針になりました。

APIのアップデート

新旧APIの違いのほとんどはスキーマの変化だけですが、一部エンドポイントでは文字列のフォーマットが変わっています。 例えば hoge/fugahoge:fuga になるようなイメージです。

アップデート作業をする時、スキーマの変更であればAPIモデルを新しいものに替えることで、シンタックスエラーが発生して作業に漏れがあるかがわかります。 ですが文字列のフォーマットの変更は漏れはシンタックスエラーにならず把握するのが難しいです。

そこで視覚的にわかりやすいスナップショットテストを使うことになりました。

挙動が変わらないことを担保するには

今回のシステムがやっていることは基本的に以下の2つです。

  1. APIからデータを取得して、DBにデータを投げる
  2. DBからデータを取得して、APIにデータを投げる

1については最終的なアウトプットである、DBに投げるデータが変わっていなければ、アップデート前後で挙動が変わっていないと言えると思います。
2についても最終的なアウトプットである、APIに投げるデータが変わっていなければ挙動に変わりが無いと言えますが、APIのスキーマが変わっているのでAPIに投げるデータはどうしても変わってしまいます。そのため投げるデータが変わっていても形式だけで表している情報が変わっていなければ挙動に変化がないと考えます。

この2つのアウトプットが変わっていなければ挙動が変わらないことを担保できそうです。

スナップショットテスト

アウトプットの変化を把握するためにアップデート前後でスナップショットを撮影します。 取得部分はモックを使ってスナップショットの撮影を行います。1はAPIのモックに実際の新旧APIのレスポンスを用いることで、より本番に近いテストが行なえます。

前後のスナップショットを比較することで、DBに保存するデータが欠損していないか、文字列のフォーマットが変わっていないか、APIに投げるデータのスキーマが変わっても表している情報は変わっていないか、APIに投げる文字列のフォーマットが古くないか、など視覚的に確認できるようになります。

この方法で無事にアップデートを終えることができました。

まとめ

今回はスナップショットを使って安全にアップデートを行う方法をお話しました。

これまでスナップショットテストはフロントで生成されるHTMLに意図しない変更が起きないか確認するものという程度の認識でしたが、いろいろな使い方ができそうです。 例えば、ライブラリの実行結果のスナップショットをとっておいてライブラリアプデ時に挙動に変化が無いことを担保する、とか良さそうな気がします。

スナップショットテストは比較的に書くのが楽だったので今後も使っていきたいです。