(Photo by: nyuhuhuu)
はじめに
テスト駆動開発(以下TDD)を始めていますか?
TDDに懐疑的で、ひとまず情報を集めようと思っている方もいるでしょう。
TDDは銀の弾丸でもないし、適当に始めてうまくいくものでもありません。TDDにも他の手法同様、陥りやすい罠(アンチパターン)があります。そのため、アンチパターンを知り、うまく回避することが成功の秘訣です。
この記事では、
- TDDを始める前に、注意点を知っておきたい方
- TDDを始めたけど、あまりうまくいっていない方
のために、TDDのアンチパターンとその対策をお伝えしていきます。TDDは簡単なようでいて、失敗しやすい開発手法です。本来の有効性を最大限に活かすためにも、ぜひご一読して、TDDを成功に導きましょう。
テストは書かれているが、必要なことがテストされていない
問題
一見、すべてのテストケースにパスしてうまくいっているように見えても、実は必要なことがテストされておらず、テストに抜けがあるパターンです。テストがたくさんあると、なんとなく安心してしまいますが、抜けのあるテストでは決して安心は得られません。
対策
このパターンは、テストを後付けで書いてしまったときに起こりやすいです。TDDの原則に従い、製品コードを書く前に、そのコードが仕様を満たしているか確認するテストを書いていればこのようなことは起こりません。テストファーストの原則を守るようにしましょう。
テストの準備をするコードが長すぎる
問題
大抵のテストでは、実際のテストをする前に、テストの準備をするコード(セットアップコード)を書かなければいけません。短いコードであれば問題ありませんが、これがテストコードの大半を占めるようになってきたら改善が必要です。このようなテストは意図がわかりにくく、何をテストしているか理解するのに時間がかかります。
対策
長いセットアップコードが必要になる場合は、テストに関連するオブジェクトが多すぎる可能性が高いです。設計を変更して依存しているオブジェクトを減らすか、モック(テスト用の仮オブジェクト)を使って、テストに関わるオブジェクトの数を減らします。ひとつのテストで、複数のオブジェクトや機能をテストしないようにしましょう。
ひとつのオブジェクトに対して大量のテストコードがある
問題
ひとつのオブジェクトのテストケースが多すぎて、テストコードが数千行になっているケース。これは、オブジェクトの責務(機能)が多すぎることを意味しています。いわゆる、「God Object」と呼ばれるオブジェクト指向のアンチパターンです。責務が多すぎるオブジェクト(クラス)は、変更に弱く、バグの温床になりがちです。
対策
オブジェクトの多すぎる責務を、複数のクラスに分割しましょう。オブジェクト指向では、関連のある機能をまとめて、凝集度(ぎょうしゅうど)を高めることが重要です。凝集度が低いシステムでは、ひとつの変更が多数のオブジェクトに影響して、連鎖的にテストが失敗します。凝集度を高めることで、変更に対する影響が小さく抑えられ、保守性を向上させることができます。多機能すぎるクラスは作らないようにしましょう。
テストがオブジェクトの内部実装に依存している
問題
原則的に、TDDのテストはブラックボックステスト(内部構造に依存しないテスト)であるべきです。テストがオブジェクトの内部を知りすぎている(結合している)と、本来外部に影響がない変更に対してもテストが失敗してしまいます。これでは、テストがリファクタリングを妨げる原因になってしまい本末転倒です。
対策
このパターンは、コードカバレッジ(テストの網羅率)100%を目指すあまり、そもそもリファクタリングが必要なオブジェクトを無理やりテストしてしまったときに起こりやすいです。外部からテストしづらいということは、設計の改善が必要だということを示しています。内部実装に依存して無理にテストする前に、設計から改善しましょう。
テストにアサーションがひとつもない
問題
通常、テストは何らかの仕様をテストしているはずなので、アサーションがひとつもないというのはおかしいのです。こういったテストは、実際には実行時エラー(例外)が発生することを期待してテストしていることが多いです。たしかに、テストは失敗するので、テストとしては成り立っているような気がします。しかし、テストを読んだときに、すぐに意図を理解することは難しいでしょう。
対策
暗黙的な実行時エラーに頼ることなく、明示的にアサーションを書きましょう。また、テスト失敗時に例外が投げられることを期待しているならば、それもテストとして書いておきます。大抵のユニットテストフレームワークには、実行時エラーを補足できる機能が備わっています。テストは、読みやすく、意図がつかみやすいものにしておきましょう。
テストに時間がかかりすぎる
問題
ひとつのオブジェクトに対するテストに時間がかかってしまうケース。あまりにテスト時間が長くなりすぎると、TDDの「レッド→グリーン→リファクタリング」のサイクルをスムーズに回せなくなり、リズムを崩してしまいます。TDDでは、このサイクルをリズムよく回すことが大切です。
対策
テストが遅くなる主な原因は、データベースやネットワークI/O、ファイルI/Oなどアクセスに時間がかかるリソースに依存していることです。モックやローカルリソースを利用するなどしてテスト時間を短縮しましょう。テストの際にコーヒーを入れ始めたら改善のサイン。
まとめ
TDDはテストをすることに夢中になってしまい、いつの間にかテストそのものが目的になってしまいがちです。TDDの目的は「テストすること」ではなく、「コード・設計の改善」や「早期のフィードバック」です。「テストが汚い」「テストが壊れやすい」というのも一種のフィードバックになります。なにかおかしいと感じたら、すぐにコードの改善を始めましょう。後になるほど傷は深くなります。「開発→フィードバック→改善」のサイクルを回し続けることがTDDの真髄です。
本ブログは、Git / Subversion のクラウド型ホスティングサービス「tracpath(トラックパス)」を提供している株式会社オープングルーヴが運営しています。
開発の効率化をしたい!もっと便利なツールを使いたい!そんなお悩みをtracpathで解決!
「tracpath(トラックパス)」は、企業内の情報システム部門や、ソフトウェア開発・アプリケーション開発チームに対して、開発の効率化を支援し、品質向上を実現します。
さらに、システム運用の効率化・自動化支援サービスも提供しています。
”つくる情熱を支えるサービス”を提供し、まるで専属のインフラエンジニアのように、あなたのチームを支えていきます。
No Comments