自動テストの意義について考える


はじめに

自動テストに関しては、賛否両論あると思います。
そんな中で、少しでも自動テストを書くようにチームの意識を変えていくには?という部分も含めて考えてみました。
ただ「必要でしょ!」というだけでは平行線なままなので、「否定派」「肯定派」のそれぞれが何を大事にしているのか?という部分も含めて整理してみました。

自動テストの導入を検討している方の助けに少しでもなればと思ってます。

私は、現在RSpecでの自動テストを導入しているプロジェクトと、自動テストを導入していないプロジェクトを掛け持ちしてます。

議題

  1. なぜ否定派と肯定派が現れるのか
  2. 必要性について
  3. どこまで書くのか
  4. 書くときに気をつけたいこと

なぜ否定派と肯定派が現れるのか

否定派の意見

テストコードを書くことよにって下記が"失われる"

  • 開発スピード
  • 仕様変更対応へのコスト
    • 仕様変更があるたびに、テストコードも変更しないといけないから

つまるところ、『開発効率』が落ちると考えられていることが多い

肯定派の意見

テストコードを書くことによって下記が"得られる"

  • 品質
  • 影響範囲調査コストの軽減
    • 1回テストを回せば全部わかるでしょ?

なぜ平行線なのか

見ている「時間」と「結果」が違う

  • 否定派
    • 「今」に重きを置いて議論している
    • 「失うこと」に重きを置いて議論している
  • 肯定派
    • 「未来」に重きをおいて議論している
    • 「得られること」に重きを置いて議論している

まずは…

同じ「時間」を見て話をすることが大事

  • 「今」を見る

    • 自動テストを書くことのメリットは?
      • プログラム設計の妥当性検証
      • テストがかけないプログラムは、十中八九プログラムとして破綻している
    • 自動テストを書くことのデメリットは?
      • テストを書いている時間分、他の開発ができない
  • 「未来」を見る

    • 自動テストを書くことのメリットは?
      • リファクタリングを積極的に行える
        • 正しい挙動が証明されているから
        • リファクタリング=動きを変えずにコードを綺麗にすること(動きが少しでも変わるものはもはや「機能追加」)
    • 自動テストを書くことのデメリットは?
      • 大きな仕様変更があった場合に、テストを書き直す工数が発生する

必要性について

上記の内容から、プロジェクトにとって必要かどうかを判断すればいい。
ただ、個人的には上記の内容をみて「不要」と判断する人はそういないと思う。
(すでに「必要」と思っている人間なので、メリットの方がデメリットより強くなってる感はありますが)

個人的には「自動テストは必要」と考えてます。

なぜ必要なのか

  • 「今」コードの妥当性を確認できる

    • テストコードを書くことで、「テストが書きづらい部分」を知ることができる。
    • 大抵の場合、そういう部分にこそ、「バグ」の芽が潜んでいる。
    • 従来であれば、プログラム稼働後しばらくたって気づく様な「臭い」ポイントに、稼働前の実装時点で気づくことができるのは大きな収穫。
  • 「今」かけるコストに以上の結果を、「未来」に得られる

    • 特にリファクタリングを積極的に行えるというのは、長く運用・保守を続けていくシステムにとっては何よりも重要な要素
    • 1年前のベストプラクティスが、1年後もそのままベストプラクティスとして通用するようなケースは少ない。
    • そのため、いかにリファクタリングをしやすくしておくかは、先々抱える技術的な負債を返却する機会を残しておくのに等しい。

どこまで書くのか

目的を明確にしてスタートしないと、「とりあえず全部書く」状態になってしまう。
正直、これではいくらコストをかけてもキリがないので、

  • 自動テストでテストすること
  • 自動テストでテストしないこと

をしっかり決めてからスタートするのが吉。
「自動テストで全てのテストを行おう」という思いを捨てることが一番大事だと思う。

まずは、プロジェクトとして「自動テストを行うことで何を得たいのか」ということを明確にすれば、自ずと「どんなテストを書く必要があるのか」ということが決まってくると思う。

例) 将来のリファクタリングを楽に確実に実行したい場合

  • テストとして書いておくべき範囲
    • 各クラスが公開しているインターフェース(public / protectedメソッド)に関するブラックボックステスト
  • 必ずしも書く必要のないテスト
    • 各クラスが公開していないインターフェース(privateメソッド)に関するテスト

上記の様に、「何を達成したいのか」というものをベースに「どこまで書くか」を決めていくのが一番いいのではないかと思う。

書くときに気をつけたいこと

自動テストもプログラミング。
従って、そこには一定の「ルール」が存在してしかるべき。

「ルール」を持ち込んだ方が良いと考える部分

  • 構造を合わせる
  • 表現を合わせる
  • 共通Moduleのテストに気をつける

構造を合わせる

チームメンバーAとBが同じクラスに対するテストを書いたときに、「構造」が違うことがない様に注意する必要がある。

RSpecではdescribe context it / exampleなどで「構造」を表現していくため、プロジェクトとして、利用シーンの統一は必須事項。

表現を合わせる

1件1件のテストケースが、そのまま「テスト仕様書」「内部設計書」となることを考慮して、「実際のテストコードを読まなくても内容が理解できる」レベルで表現を統一するべき。

共通Moduleのテストに気をつける

共通モジュールを利用しているそれぞれのプログラムで、同じテストを書かない様にする
共通モジュールに変更があった場合、利用側は「テストコードが変更されていないがテストが失敗する」という結果になるようにテストを書くべき。

おわりに

自動テストの実施に関して、思う部分を書いてみました。
多くのプロジェクトですでに利用されている技術ではあると思いますが、改めて整理してみることで見えてくる部分もあるかなと思います。

明確な答えがないからこそ、「プロジェクトとしての答え」を明確にしておく必要があると思っています。