プログラマが知るべき97のこと/不具合にテストを書いて立ち向かう

テストを行っている品質保証チームや、実際にシステムを使っているお客様から不具合が報告されたとき、あなたはどう思いますか? 悲しんだり、恥ずかしいと思い、不具合修正にすぐに着手したいと気がはやるというのが人情というものです。しかし、焦っているときに行う作業はしばしば視野が狭く、1つの不具合修正が3つの新たな不具合を生んでしまうということになりがちです。

テスト駆動開発(TDD:Test Driven Development)とは、プログラマが自分の不安を克服し、自分が書くコードに自信を持ちながら一歩一歩進んでいくための手法です。しかし不具合の発生とは、端的に言えばこれまでの「自信」を揺らがせる事態です。テスト駆動開発者は不具合にどう立ち向かうのでしょうか?

やはりテストを書いて立ち向かってゆくのです。私はテスト駆動開発を数年間実践してくる中で、心がけているひとつの「掟」があります。それは、「不具合の修正時には必ず先に不具合を再現する自動テストを書いてから修正する」というものです。これはもちろん私の発案ではなく、XP(eXtreme Programming)やTDDの先達から学び、それを実践するうちに私にも身についてきたものです。不具合修正時のテストは、次のような手順で行います。

  1. 手元で不具合を再現させる。
  2. コードを注意深く調べ、不具合を発生させている最小の部分を絞り込む。
  3. 最小レベルで不具合を再現させ、不具合が修正されたら通るような自動テストコードを書く。
  4. 3で書いたテストコードを実行し、落ちることを確認する。
  5. 不具合を修正する。
  6. 3で書いたテストコードが通ることを確認する。
  7. 既存のすべてのテストを実行し、不具合修正が他の部分を壊していないことを確認する。

こう書くと面倒に感じるかもしれませんが、不具合修正時のテストには、さまざまなメリットがあります。

  • 不具合が本当に自分の考えた原因で発生しているかが明らかになる
バグ修正は「当てもの」です。どんな原因で不具合が発生しているのかを、プログラマは推理しなくてはなりません。不具合再現のテストが落ちることを確認することで、「ここが原因だろうと考えて修正したら、全然違う場所が原因だった」というような事故を避けることができます。また、不具合修正に未着手のうちにテストが成功した場合、テストにバグがあるか、考えている不具合の原因が異なるのか、とにかく自分の理解がまだ浅いことを意味しています。
  • 対象コードと対象領域に対する理解が深まる
最小単位を探すという行為は原因を深く追い、考えることにつながります。不具合はなぜ発生したのでしょうか。対象領域の理解が浅かったのかもしれません、コードが読みにくかったのかも知れません。不具合修正は新機能の追加とは異なり、既存のコードに対する調査です。これは既存のコードと対象領域に対する理解を深める良い機会になります。
  • 自分の弱点、気づきにくい点がわかる
自分ではしっかりとテストを書いているつもりなのに不具合を世に出してしまったということは、自分の思い至らなかったテスト、視点があるということです。自分の弱点や気づきにくい点は、普段コードを書いているだけでは得られない視点であり、非常に貴重です。また、不具合修正時のテストを書くときには、同様の過ちを犯している箇所は無いかを必ずチェックしましょう。プログラマも人間ですから、同じような過ちを犯している場合があるのです。
  • テストの堅牢さ、価値が上がる
自動テストの利点は、いつでも同じように実行できることです。不具合修正を自動テストの形にすることで、不具合が本当に直ったか即座に確認できます。さらにその自動テストを残しておくことで、今後不具合が再発した場合でも、テストが落ちることによってすぐにわかるようになります。不具合を克服して立ち上がるたびに、テストコードの網羅性は上がり、既存コードに対する自信も深まります。

「テストを書いている時間は無い」と言われたり、不具合修正時にテストを書くことをひどく遠回りに感じることがあるかもしれません。しかし、患部の絞り込み、修正中の確認、他の部分への影響の確認、再発防止などを考えると、不具合修正にテストを書いて立ち向かうのは合理的で効率的な手法なのです。テストを友として自信を持ちながらコードを書く。それがテスト駆動開発を身につけたプログラマの仕事のやり方です。