はじめに
こんにちは、テックリードのかどたみです。今年最後の記事なのでポエム回です。
私が入社して約3年、入社当初はテストが無かったり、テストが意味をなしていなかったりして改善活動に励んできました。昨年中頃までは既存のプログラムのテストについて考えていて、その後マイクロサービスの開発が始まったため新規で立ち上げるプログラムのテストと向き合っています。
この記事では、テストに向き合ってきた結果感じたことを振り返り、立ち返るポイントとして残しておきます。
この記事はエモーションテック Advent Calendar 2022の14日目の記事です。
テストの目的
さて、まず私のテストの目的を明確にしておきます。みなさんがテストを書く目的は何でしょうか?
- 一定のカバレッジを担保することが規約に含まれているため
- 自分の書いたプログラムの動作確認のため
- 手動テストの時間やコストの削減のため
上記のように色々なものがあると思いますし、私もこのように考えていたこともあります。しかし、現在ではどれだけチームメンバーが精神的に健康でいられるかが第一目的として挙げられます。
既存のプロダクトでも解消されては来ましたが、機能改修やライブラリバージョンアップの度にデグレが発生する危険と戦いながら業務を行うことが多いという問題があります。どんなに熟慮して書いたプログラムでもどこかが壊れてしまうかもしれないと思いながら業務をするのは健全な状態ではありません。
テストがしっかりと書かれていればそのような危険と戦わずともリリース前にバグを検知することができるはずです。
また、設計改善などのリファクタリングをしたい場合、幾ら中身を変えたとしても外からの振る舞いがテストで担保できるので絶対にバグを出すことはありません。リファクタリングをする際の安心感もとても大事になってきます。もし、リファクタリングがしにくいと、その結果として稚拙な設計のままプログラムが肥大化し、技術的負債が増えていくことにも繋がります。
追加機能を作るときはもちろんのこと、運用保守の面でも安心してプログラムを書き換えることができるというのはサービスの品質を向上・維持するためにもとても重要です。ということでこの記事の執筆時点での私は精神的に健康でいられることを一番の目的としてテストを書いています。
カバレッジは役に立つ?
さて、ではどういう状況になればテストが書けている、精神的な健康を保てると言えるのでしょうか?精神的な健康を保てるテストというのはどこかのプログラムを変更したときにバグが発見できる・もしくはバグがないことが確認できるテストだと思っています。
テストとして当たり前じゃないか!と思う方もいるかも知れませんがそれが当たり前でない環境も存在するということは知っておいて損はないかと思います。
テストを導入するとまず、テストを書こう!カバレッジをあげよう!という考えに至ります。そして、テストを書く作業に囚われてテストの意味を考えなくなっていく事があります。
カバレッジも大切なのですが、カバレッジだけでは精神的な健康を保てません。実際、既存のプロダクトは入社当初カバレッジが85%と低くない水準にありました。しかし、精神的な健康を保てる状態ではありませんでした。なぜでしょう?
カバレッジが高くても意味をなさない以下のようなテストが存在するからです。
このようなテストはバグが全く検知できません。例えば、永続層のSQLにおいて返却値の件数しかテストされていないとすると、カバレッジは100%ですが、order byのdescをascに書き換えるだけでテストが通るバグを埋め込めます。
また、カバレッジを上げることを目的とし、private methodがテストされているものもありました。private methodをテストすべきかという問いに答えてくれる有名なサイトを御覧ください。
テストというのは外から見た振る舞いを検証しなければなりません。private methodを使うかどうかは手段の一つにすぎず、実装の関心事であり、振る舞いではないためテストを書くべきではありません。
private methodをテストしてしまうと、リファクタリングをしていても外部からの振る舞いが正しいはずなのにテストが落ちることになってしまいます。これはカバレッジに囚われて逆に精神的な健康が保てなくなる良い例です。逆に言うとprivate methodをテストしないとカバレッジが担保できないコードは、設計や責務が正しくないのでリファクタリング対象としてマークするべきです。
しかし、逆にカバレッジを必ずしも上げなくても良いプログラムもあると思っています。 例えば
- ユーザーのセッション情報を使い回すinterceptor
- 依存する外部のツール(例えばDB)のエラー処理に関するコード
などのテストです。
なぜかというと、前者の場合は基本的に全機能がバグるので開発環境などで動作確認すればバグを検知できる可能性が高いため、後者は数あるDBを利用する関数の中で毎回DBが落ちた時用のモックとテストコードを用意するコストがかかり、本質的では無いため1箇所でも書いてあれば十分です。
両者ともカバレッジを上げても精神的な健康の担保にはつながらないと考えています。
あくまで上げなくて「も」良いです。工数などその他の要因で優先度を下げられるテストです。記述するコストが低いのであればもちろん書きましょう。
カバレッジは重要な指標ですが、カバレッジにとらわれること無くテストを書く目的を果たしていきたいですね。
結局行き着く先は同じ
ここまで色々書きましたが、精神的な健康を担保できるテストをカバレッジ以外で評価できるのでしょうか?
私はかなり難しいと思っています。そもそも精神的な健康度合いは定量的に測れませんし、バグの発生率や改善速度などを測ることはできますが、テストを書かなかった世界線と比較することはできないですよね。
カバレッジも100%を目指さなくても良いというスタンスではありますが、ではどういう場合は100%じゃなくて良いなどを定義するのも難しそうです。
そういった意味では100%には最低限しようというのは楽ではありますが、前述の通り100%だから大丈夫ということもないです。
結果、設計の改善活動で至った結論と同じく、「初めから完璧なものを目指そうとするよりも手を動かしつつ議論しながらブラッシュアップさせていった方が良い」が答えな気がしています。
何が最適で何が良くないのかは環境によって左右される気がします。弊社は自社開発のwebプロダクトを作っていますが、納品型のプロジェクトや、webではないプロダクトの場合は考え方もきっと異なるでしょう。
その時々で目的に沿った最適なテスト方法を議論できるチームで有りたいですね。
おわりに
いかがでしたでしょうか?今回はテストに関してポエムを詠ませていただきました。 テストを目的とせずテストの先にある目的のために手段としてテストを極めていきたいですね。
エモーションテックでは顧客体験、従業員体験の改善をサポートし、世の中の体験を変えるプロダクトを開発しています。プロダクトに興味のある方、価値のあるテストを資産として保守しやすいプロダクトを作ることに興味がある方、ぜひ採用ページからご応募をお願いいたします。