Shoichi Matsuda's diary

このブログは移転しました。 https://shoma2da.net/ が新しいブログです。

テストがないコードをどのようにテストしていくか

みなさんテスト書いてますか?
最近のプログラマ界隈ではテストや自動化の話題が非常に多くなっていますよね。
そんなことを言いつつ僕もつい最近テストについて発表しました

テストが書けるようになってくると実装に自信が持てたり、変更を恐れなくなったりなど良いことが非常に多いです。

基本的には是非書いたほうが良いテストですが、実際の開発現場ではそう簡単にいくものではありません。
これまでに誰か(もちろん自分でも!)が書いたテストのないコードに手を入れていくことが非常に多いのではないでしょうか。

リーン開発の現場にこうしたレガシーコードについての戦略が記載してあったというのもありますが、自分自身もこのような状況に出くわすことが多いので今の思いをまとめておきます。

どうやってテストしていく?

実際にテストのないコードをテストしていこうとする場面を想像してみてください。
僕の知っている中では選択肢として以下の2パターンが挙がることが多いです。

  • チーム全体でテストを書くことを決意して、一気にテスト環境やテストを揃えていく
  • コードの修正や追加をしていく際に必ずテストを付けるようにして少しずつテスト環境やテストを揃えていく

結論を言うとほとんどの場合、後者がベターな選択肢ではないかと考えています。
そのように考えている理由を説明していきます。

この2パターンは「テストをすること」に関してははチーム全体の合意が取れている前提のものです。
名著レガシーコード改善ガイドでは「編集して祈る」か「保護して変更する」かという2パターンの方法ついて述べています。
しかしこれらはあくまで修正の方法論について述べているものですので上記とは意味合いが異なります。

それで、誰がテストに詳しいの??

仮に先程述べたうちの前者、「チーム全体でテストを書くことを決意して、一気にテスト環境やテストを揃えていく」を選択したとします。

ではテストを書きましょう!となりますが、実際問題としてテストに詳しい開発者はそう多くないはずです。
(一方ではてなやクックパッドはテストに関してかなり先行していそうですね。すごい!!)

そのような状況でテストを初めてしまっても、そもそもテストの粒度や書き方を学ぶのに相当の時間的コストがかかってしまいます。

また、テストするということはプロダクトのコードにもほぼ必ず手を入れることになります。
(テスト不可能だったりそのままのプロダクトコードだと非常に複雑なテストを書かなければならない場合が出てくるため)

テストへの理解があやふやなまま、テストができるようにプロダクトコードを変える。
これは非常に危険なことではないでしょうか?

実装が非常に簡単、といった箇所であれば問題ないかもしれませんが「一気にテスト環境やテストを揃えていく」と決めるということは、そのような箇所だけではなく全ての箇所を見ていくことになります。

長い期間書けてテストを揃えたけど、プロダクトとしての動作を保てなかった...では全く意味がありませんよね。

そこってほんとに手を入れるべき??

ソースにはどうしても「良く変更する箇所」と「全然変更しない箇所」が出てきます。

このうち「良く変更する箇所」については是非とも早めにテストを用意しておくべきでしょう。
変更ごとにテストを実行することによって安心してプロダクトに組み込んでいくことができます。

一方で「全然変更しない箇所」はどうでしょうか。
もう少し詳しく言うと「全然変更しないけど期待通り動いている箇所」です。
結論から言えばこうした箇所のテストは後回し、更にいえばそのままずっとテストなしでも問題ないのではないかと思っています。
(ここに対する意見は人それぞれ大きく異なりそうな気がしています)

冒頭に述べた後者の選択肢「コードの修正や追加をしていく際に必ずテストを付けるようにして少しずつテスト環境やテストを揃えていく」としていればこうした箇所は触れられることはなく、半自動的にテストされないままになります。

昨今のソフトウェア業界は以前にも増して更に加速度を増しています。
「今は修正の必要がないけどテストコードでより高い安全性を確保する」よりも「新機能の追加や既存の不具合を修正」を素早く行ってユーザに価値を届けていくことの方に基本的には重点を置くべきではないかと思います。
(テストを揃えておくことはもちろん大事ですよ!!念のため。)

YAGNIという言葉もありますし、過度な先読みは最終的には無駄な作業を生む可能性を考えると良いのではないでしょうか。

自動化も一緒にやる??

テストを書いていくとJenkinsなどを使って自動化(CI)したくなってきます。
確かにコミットしただけでビルドやテスト、デプロイなどを自動で行えることは革命的に素晴らしいものです。

しかし、テストと合わせて自動化ツールもほぼ同時に導入しようとするのには少し考えなおした方が良いかもしれません。

テストを書いていくとテスト用のデプロイ環境やダミーの入力値の準備といった周辺環境の念入りな準備が必要になります。
自動化ツールはあくまで手動で実行できるものをトリガーのタイミングで実行させるだけのものです。

テスト自体の周辺環境があまり固まっていないのに自動化ツールを導入すると、 テストの周辺環境を変える→テストが通ることを確認する→!!自動化の設定を変える!!→!!自動化できているか確認する!! などと自動化に関する工程が増えてしまいます。

テスト自体に慣れてきていれば自動化の設定変更は苦にならないかもしれませんが、テスト自体があやふやなのに自動化についても気にしなければならない!となると精神的負担も非常に大きくなってしまいます。

楽になるための自動化ツールで苦しくなってしまっては元も子もありませんよね。

まとめ

テストのないコードに対するテストをどう行っていくかについて述べました。

一気にテスト環境を整えきろう!と意気込んでしまいがちですが、その方法ではスーパーエンジニアでもない限り失敗してしまうことが多いのではないでしょうか。

個人的には「コードの修正や追加をしていく際に必ずテストを付けるようにして少しずつテストの環境やテストを揃えていく」という選択がベターな気がしています。
テストを少しずつ書いていくことによってテスト自体(あるいはプロダクトの特徴など)に慣れ、それを続けていくことで環境が整い自動化していける、といった少しずつ前に進んでいく手順です。

是非みなさんも考え、実践してみてください。
また、より良い方法などあれば是非教えていただきたいです!