自分がWebアプリのサーバーエンジニアとして単体テスト・結合テストのコードを書くにあたって、そもそもの前提として「テストの区分」って自分の中でどんな認識だっけ?をアウトプットしておこうと思って記事化。
1. テストの区分
①単体テスト(ユニットテスト)
- 関数・メソッドについて、別の部品(クラス・関数・メソッド)の影響を受けることのないテストコードを記述してテストすること
- テスト対象の内部に含まれる別の部品はモック化するなどして実際の実装の影響を受けないようにしてテストコードを書く。
- テストケースは、「関数・メソッドのコメント」に基づく「ブラックボックステスト」を基本とし、「コメント」に載っていない詳細仕様の部分については、「ホワイトボックステスト」にする
- その部品単体がちゃんと動いているかをチェックするだけであり、アプリが仕様通りか?について担保されるわけではない。
- 内部で他の関数・メソッドをたくさん呼び出すようなものには向かない(別部品をモック化してテストOKだったとしても、そいつらの占める割合多いせいでテストの存在価値が低い)
- アプリの実装によく使うようなライブラリの関数・メソッドに向く
②結合テスト(統合テスト)
- 部品同士を組み合わせ、想定している動作をしているかのテスト。「部品」同士の粒度は様々であり、この言葉がカバーする範囲は広く曖昧。
- アプリ内に含まれる関数・メソッドのテストであれば、その中に含まれる小さな関数・メソッド群の影響も考慮(=モックを使わない)したものになるだろうし、その中でもAPIのテストであれば、DBとの連携(マスタデータ、ユーザーデータの状態も考慮)も考慮したものになるだろうし。
- APIの実行方法をとっても、実際にクライアントアプリ側から叩いてのテストもあれば、APIを叩いたときの開始地点である関数・メソッドを直接実行してのテストもある。
③E2Eテスト
- 本番に近い状態でアプリを操作するテスト。ユーザー目線でのテスト
- 製品としての品質の担保をするための一番重要なテスト。
2. 各テストの力の入れ具合
それぞれの区分でどんだけテストすればいいんだよっていう話だが、過去の経験的に以下のような形になると思ってる。
※サーバーエンジニア/クライアントエンジニア/QAエンジニアのチームではっきりシステムがわかれているWebアプリ開発現場を想定
①E2Eテスト
※システム内部を知ってるサーバーエンジニアが担当するとどうしてもユーザー目線が損なわれることがあるので、基本的に第三者(QAエンジニアとか)が担当するのが妥当。
- 製品としての品質を担保するもっとも重要なテストであるため、手を抜くべきではない。
- 以下を確認する。
- アプリが仕様書通りであるか(状態に応じた画面構成、画面遷移)
※テストケースは「条件・期待結果」をわかりやすく記述して、関係各所(ディレクター・クライアントエンジニア・サーバーエンジニア)でレビューして認識に齟齬がないことまで確認しておく
仕様書で語られてない部分は仕様書について責任を持つ人(だいたいディレクターじゃね)に仕様を確認する - ユーザー体験として違和感がないか、親切であるか
- アプリが仕様書通りであるか(状態に応じた画面構成、画面遷移)
②結合テスト
-
API実行
- サーバーチームが責任を持つシステムとして、想定してる仕様が満たせているか?をチェックできるので最も力をかけるべき。
- 理想としてはすべての状態を考慮したテストケースがここにまとまっていれば、内部のロジックを変更しても、全体の動きとしての想定に食い違いがないかに気付ける。
- 細かな状況は内部で呼ばれてる関数・メソッド単位でチェックしてもいいんじゃない?という意見も出やすいが、個人的には内部で呼んでいる関数・メソッドの仕様が変わったり削除されないという保証もなく、この状況でのテストってどこで担保されてんだよ・・・・ってなりがち
-
その他関数・メソッド
- 再利用されるような関数・メソッドは、その動作の信頼性を担保できるのでテストを実装する価値がある。
- やろうと思ったらキリがないので、API実行レベルでのテストを実装した上で余裕があったらって感じ。
- ・・・が、仕様変更やコードレビュー指摘で対象の関数・メソッド自体が不要になっちゃったり、大きく構造が変わった場合の再コーディングのコストや精神的ダメージがデカいため、そんなに力をかけるべきではない。もっともコスパ悪いのは「unexported, privateなサブルーチン」であり、テストコード実装してる現場は多くないんじゃないだろうか。
-
サーバーxクライアントのつなぎこみ: 主要な動作くらいはちゃんと手動でクライアントアプリ経由でテストし、E2Eテストしてもらうレベルには仕上がってることを担保しておく。
③単体テスト
- ライブラリ
- 便利関数系はモックを使う箇所が少ないだろうし、相性がいい。
- 実際にアプリケーションコードで使っているものはちゃんとテストコードを書いておいた方がいい。特に外部ライブラリは、自分たちのアプリの要件を満たす動作をしているかという受け入れ検証の意味も込めて。
3. 結論
・・・・っていうか自分の認識では、結合テストと単体テストの違いって不純物が紛れているかどうかなだけだと気づいた
で、テストコードがんばって記述する価値があるのは、
API実行 >= ライブラリ > その他関数・メソッド(public) > > > > > > > > > その他関数・メソッド(private)
っていう認識。