テスト駆動開発入門: コードの質を高める5ステップ
第3話:コードを書く - レッド、グリーン、リファクタリング
(最終更新日:2023.2.23)
(絵が小さい場合はスマホを横に)
「テスト駆動開発のサイクルを回そう!」
前回はテストケースの構造、シンプルな機能のテストを書く重要性を説明した。
今回は、実際行うテスト駆動開発のサイクルに沿って、コードをリファクタリングするところまでを紹介する。
1.レッド: 失敗するテストを書く
テスト駆動開発(TDD)のサイクルの最初のステップは「レッド」フェーズだ。 この段階の目的は、失敗するテストを書くことにある。 このプロセスは、新しい機能や修正が必要なバグに対する要件や期待を具体化する役割も果たす。 レッドフェーズは、実際にコードを改善する前に、その改善点を明確にすることで、開発の方向性を定める重要な役割を担う。
■失敗するテストの書き方
- 要件の明確化: 実装したい機能や修正するバグについて、具体的な要件を明確にする。この要件は、テストを通して表現される。
- テストの作成: 要件をもとに、それを満たすためのテストケースを作成する。このテストは、現在のコードベースでは失敗することが期待されるものだ。テストが成功するような機能実装やバグ修正は行われていない。
- テストの実行と失敗の確認: 作成したテストを実行し、実際に失敗することを確認する。 この失敗は、開発の出発点となり、次にどのようなコードを書くべきかの指針を提供する。 失敗するテストが存在することで、新しいコードが正しく機能しているかどうかを検証する基準ができる。
■失敗するテストの意義
- 開発の目標を明確にする: 失敗するテストを書くことで、実現したい機能や修正すべき点に対する明確な目標を設定する。これにより、開発者は目的に集中しやすくなる。
- 品質保証の基盤を構築する: 最初からテストを書くことで、新しい機能や修正が正しく動作することを保証するテストカバレッジを確保できる。品質の高いソフトウェアを開発する上で不可欠だ。
- リファクタリングの安全性を確保する: 後のリファクタリングフェーズでコードを改善する際、 既に存在する失敗するテストが成功することを確認することで、 リファクタリングによって新たなバグが導入されていないことを保証できる。
レッドフェーズはTDDのサイクルにおいて、開発プロセスの出発点となる重要なステップだ。 このフェーズを通じて、開発者はソフトウェアの要件を深く理解し、目標を明確に定めることができる。
実装すべき要件を明確に
2.グリーン: テストをパスする最小限のコードを書く
テスト駆動開発(TDD)のサイクルの次のステップは「グリーン」フェーズだ。 この段階の目的は、先に書いた失敗するテストをパスするための最小限のコードを書くことにある。 ここでの焦点は速やかにテストをパスさせることである。この時点でコードの品質や構造については二の次になる。
■グリーンフェーズのプロセス
- 最小限のコードの実装: テストが失敗する原因を取り除くために、必要最小限のコードを書く。この時、コードの美しさや再利用性は考慮せず、ただ単にテストをパスさせることだけに集中する。
- テストの実行: 実装したコードがテストをパスするかを確認するために、テストを再度実行する。このステップでは、先に書いたテストがグリーン(成功)になることを期待する。
- 必要に応じたコードの調整: テストをパスできなかった場合は、コードを調整して再度テストをパスさせるようにする。このプロセスを繰り返し、すべてのテストがグリーンになるまで実装を続ける。
■グリーンフェーズの意義
- 実装の検証: グリーンフェーズは、要件を満たすために必要な最小限のコードを明らかにする。これにより、機能の実装が正しく行われているかを迅速に検証できる。
- 進捗の確認: テストがグリーンになることで、開発の進捗を具体的に確認できる。これは、開発プロセスにおいて重要な役割を果たす。
- 次のステップへの準備: テストをパスする最小限のコードを書くことで、次のリファクタリングフェーズに向けての準備が整う。コードがテストをパスしているため、安心してコードの品質や構造を改善することができる。
グリーンフェーズでは、速やかにテストをパスさせることに重点を置く。 このアプローチにより、機能が正しく動作することを確認した上で、コードの改善に焦点を移すことができる。 グリーンフェーズを経ることで、開発プロセスが前進し、品質の高いソフトウェアを効率的に構築する基盤ができる。
最小限でテストをパスさせる
3.リファクタリング: コードの品質を改善する
テスト駆動開発(TDD)のサイクルの最後のステップは「リファクタリング」フェーズだ。 この段階では、テストをパスするコードを書いた後、コードの品質を改善することに焦点を当てる。 リファクタリングは、機能を変更せずにコードの構造を改善するプロセスだ。 このプロセスを通じて、コードの可読性、保守性、再利用性を高める。
■リファクタリングのプロセス
- コードの評価: 最初に現在のコードベースを評価し、改善の余地がある部分を特定する。これには、重複したコードの削除、より適切な名前の適用、大きな関数やクラスの分割などが含まれる。
- 小さな変更を実施: リファクタリングは、一度に大きな変更を加えるのではなく、小さなステップで進めるべきだ。これにより、各変更が意図した通りの効果を持つことを確認しやすくなる。
- テストの実行: 各リファクタリングのステップ後にテストを実行し、変更が既存の機能に影響を与えていないことを確認する。テストがパスすることは、リファクタリングが成功した証拠になる。
■リファクタリングの意義
- コードの理解を深める: リファクタリングを行うことで、開発者は自分の書いたコードやチームメンバーが書いたコードをより深く理解する機会を得る。これは、長期的なプロジェクトの成功に寄与する。
- 将来の変更を容易にする: 構造化され、整理されたコードは、将来の機能追加やバグ修正を容易にする。リファクタリングにより、コードの柔軟性が高まり、新しい要求に迅速に対応できる。
- バグの発見: リファクタリングのプロセス中に、以前は見過ごされていたバグや問題点が明らかになることがある。このプロセスは、コードの全体的な品質を高める機会を提供する。
コードを改善し、理解を深める
4.実践: サンプルアプリケーションを用いたTDDサイクル
テスト駆動開発(TDD)のサイクルを実践的に理解するために、簡単なサンプルアプリケーションの開発を例に、TDDのプロセスを具体的に見ていこう。 この例では、Pythonを使用して、簡単な文字列処理機能を開発する。本プロセスを通じて「レッド」、「グリーン」、「リファクタリング」の各ステップを探る。 この機能では、与えられた文字列から特定の文字を削除する。「hello」から「l」を削除して「heo」を返す機能である。
1: レッド - 失敗するテストを書く
最初に、新しい機能に対するテストケースを作成する。このテストは、特定の文字が削除された結果を検証する。
まずは失敗するテストを書く
2:グリーン - テストをパスする最小限のコードを書く
テストをパスするために必要な最小限のコードを実装する。この時点での実装は、可能な限りシンプルにする。
このコードはテストをパスするが、大規模なアプリケーションでの再利用性や拡張性を考慮すると、リファクタリングの余地がある。
機能を実装する
3: リファクタリング - コードの品質を改善する
テストがグリーンになった後、コードの構造を改善するためのリファクタリングを行う。
例えば、将来的に文字列処理機能を拡張する可能性を考え、機能ごとにモジュール化することを検討する。
この変更により、StringProcessorクラス内に新しい文字列処理機能を追加しやすくなる。
リファクタリング後も、変更したコードがすべてのテストをパスすることを確認する必要がある。
コードをきれいにする
■実践のポイント
- テストの重要性: テストは、機能の要件を正確に捉え、コード変更後も期待通りに機能することを保証する。
- リファクタリングの機会: テストをパスした後にリファクタリングを行うことで、コードの可読性や再利用性を高め、将来の拡張を容易にする。
- 継続的な改善: TDDサイクルを繰り返すことで、コードベースを継続的に改善し、品質を高めていくことができる。
本例では、リファクタリングを通じて、より拡張性の高いコードベースへと進化させるプロセスを示した。 TDDは、このような継続的な改善を促進し、より良いソフトウェア開発を実現する。
5.まとめ
今回は、実際にテスト駆動開発のサイクルをコードを通して回した。 TDDの「レッド」では失敗するテストを先に書き、「グリーン」でテストをパスする最小限のコードを実装する。 最後に「リファクタリング」でコードの品質を向上させ、保守性と再利用性を高める。 本サイクルの実例を見て、品質の高いソフトウェアを効率的に開発できることを理解できたと思う。
▼参考図書、サイト
「テスト駆動開発」はプログラマのストレスを軽減するか? @IT
テスト駆動開発(TDD)でコードを書く Zenn