テストコードを実装する様になって1年ぐらいたったのですが、そこできづいたことなどを。
Contents
タイトルをわかりやすく
後述しますが、仕様書としての目的があるため、関数名をなるべくわかりやすくすることがポイントかなと思います。この辺りは日本語で書いてもいいかもしれません・・・
正常系1、異常系1・・・などだと意味不明なので、なるべくなにをテストしているのかがはっきりわかるようなテストが望ましいです。
値をなるべく具体的に書く
configやenvの値などを関数で値をもってくるのではなく、直の値で直接かくようにしましょう。
- 設定が変わったことにきづかない
- 後述するテストコード=仕様書の役目がおちてしまう
疑似的な仕組みはなるべく避ける(例:Mock)
APIや外部環境などとの結合ではMockをつかったりすることもありますが、どうしてもMockを使わないと行けない場合(APIの制限がある、開発途中で呼び出せない)以外は、なるべく本環境に近い環境でテストをするのがよいです。
Mockをつかっていると依存度が下がる・・・などのメリットもありますが、呼び出し側が変わったか、つなぎ目の検証ができないためです。
仕様書として機能させる
テストコードの品質としてカバレッジが一通りの目安にはなりますが、最終的には仕様書のように機能するのがベストだと思っています。
そのため、単に動作正常性を担保するのではなく、ビジネスロジックをしっかりと担保しているか(前提データなどがそれに則っているか)を注視しましょう。
粒度の統一
例えばAPIのテストをする場合でも、大まかにざっくりわけると
- 全体を通したテスト
- バリデーションのみのテスト
- モジュール間のテスト(ServiceなどAPIの一部で使われているものもそうですが、Modelなどの単体テストなども。)
など部分ごとに分けられると思います。カバレッジをつかって見た目100%にしても粒度が整っていないと仕様書としての機能が弱くなるため、粒度の統一は必要になってくるでしょう。
テスト同士の依存をうまないようにする
あるテストコードからあるテストコードを呼び出さないようにしましょう。
よくあるケースとしては初期データ投入などですね。
この場合、traitなどで独立したクラスを作るか、factoryパターンなどでデータを簡単に作れる仕組みづくり、またマスタ系に関してはseederとして独立させるのがよいです。
時間軸をずらす際の注意
時間がたったことを確認したり、測定したりするテストが結構あるかとおもうのですが、不用意に埋め込むとテストのたびに成功と失敗が入り混じるようなflakyテストになります。
時間を経過させる場合、sleepを使ったりすることが多いかと思いますが、不用意にこれを使うのではなく、時間を固定するような関数(LaravelでいうとところのsetTestNow)を使うようにしましょう。
異常系に関しては棲み分けを
異常系のテストですが、できるものできないものをわけましょう。
できない(テストしなくて良い)ものに関しては、完全な500エラータイプでDBが落ちているとかそういったケースでないと試せないタイプです。
そういったケースは起こり得ないのでMockを使ったりしない限りは起こすことが難しいため、テスト不要かと思います(DBを落として無理やり実行するなどもありえますが・・・)。
逆に500以外の起こり得るエラー(NotFoundException、ValidExceptionなど)はしっかりとテストするようにしたほうがよいでしょう。