私はTDDに不慣れで、方法論について疑問に思っています。
与えられた:
コンソール電卓などの機能を実装するシンプルなプロジェクト。
次のような構造になっています。
また、ユーザーインターフェイスを介して実行するプロジェクト全体の受け入れテストのニースの完全なスイートがあるとします。
内部ビジネスロジッククラスの単体テストスイートが必要ですか?受け入れテストスイートを90%複製するためです。
追加だが密接に関連する質問:
たとえば、その受け入れテストスイートの実行に30秒かかる場合、質問の答えは変わりませんか? 5分? 1時間?
内部のビジネスロジッククラスがまだ実装されていない場合、その開発をガイドするための単体テストのスーツを作成する必要がありますか、それとも受け入れテストのみを残しても問題ありませんか?
単体テストのスイートが必要ですか?.
単体テストはそれ自体に終わりはありません。「特定の目標を達成したい場合、単体テストのスイートが必要ですか?」作成するソフトウェアが外部から「ブラックボックス」として正しく動作することを確認するだけの場合は、受け入れテストのみが必要です。
しかし、ビジネスロジックが(1つの大きな「神」クラスではなく)小さなコンポーネントに適切に構造化されることも目標であり、その各コンポーネントが正しく動作する必要がある場合は、そのコンポーネントごとに単体テストが必要になります。コンポーネントがある理由は、これによりソフトウェアがより進化しやすくなり(新しい要件を追加するのが容易になります)、より保守しやすくなります(新しい要件を追加し、既存のコードを変更する必要があり、受け入れテストにより、バグが導入された場合、単体テストはそのバグの根本原因をより迅速に特定するのに役立つ場合があります)。
つまり、要点は-ユニットテストはunitsが存在する場合にのみ意味があります。
内部のビジネスロジッククラスがまだ開発されていない場合、その開発をガイドするユニットテストを作成する必要がありますか?
TDDはnotテストスイートを事前に記述することについてです。それはユニットテストとコードを「ほぼ並行して」書くことです(「テストを書く-コードを書く-リファクタリング-リンスして繰り返す」)。
編集(コメントへ):受け入れテストを実施している場合、プログラムは正常に機能します。ユニットテストを導入する直接の理由はありませんまだ 。
しかし、コード内の何かを変更する必要があり(おそらく新しい要件が原因で)、TDDを実行したい場合は、変更したいコードの部分に対してユニットテストの記述を開始することをお勧めします( 「完全なテストスイート」ではありません)。
たぶん、あなたは現在の振る舞い( "緑")を検証する関数のテストから始めるかもしれません。受け入れテストは、この段階でバグを導入することを防ぎます。次に、テストを変更するか、追加のテストを追加して、意図した動作を確認します(これにより、ユニットテストが「赤」になります)。その後、新しい機能を関数に追加します(これにより、テストが再びグリーンになります)。そして今、重要な部分が来ます:関数が非常に複雑になってリファクタリングするかどうかを確認しますnow-これは、先ほど紹介したテストのために非常に簡単に実行できます。
したがって、(TDDコンテキストでの)単体テストの考え方はではありません受け入れテストの目的を複製するのではなく、実際のコーディングと低レベルの設計の改善。
少なくとも3層のコード、プレゼンテーション層、アプリケーション/ドメイン層、および永続層があると仮定しましょう。
受け入れテストはアプリケーションのスタック全体を実行するため、バグが発生すると、バグが発生した可能性のある場所がかなり多くあり、単一のテストケースのコードを最初に最初に実装した後、複数のバグが存在する可能性があります。バグの検出にはかなりの時間がかかる場合があります。
しかし、これらの各層をテスト駆動の方法で開発すると、バグを早期に発見できる可能性がはるかに高くなり、バグの場所がより明確になります。したがって、バグの修正に費やす時間を大幅に短縮できます。
また、TDDはテストdrivingの実装に関するものであることも覚えておいてください。 TDDを実践するとき、あなたは常に焦点をテストから実装に変えています。このコンテキストの変更は、コード内のパターンを発見する方がはるかに簡単であるため、スループロセスにとって正常です。一方、実装のみに集中すると、実装の詳細に頭を悩ませてしまい、全体像を把握できなくなります*。
この最後の部分では、個々のソフトウェアコンポーネントの単体テストを作成する必要があるかどうかについて、理由をあまり書きませんでした。しかし、質問の一部としてTDDについて言及していて、私が焦点を当てたかったので、そのTDDは単体テストの記述についてだけではないではなく、開発プロセスの詳細です。
TDDのプロセスの詳細については、ケンベックの本をお勧めします。 テスト駆動開発:例による
*ペアプログラミングが効果的である理由の1つは、タイピングをしていない人が全体像についてより自由に考えることができるためです。
あなたの例には複数の責任があります。それらすべては、独自のテストでカバーする必要があります。
受け入れテストは、最初に作成する高レベルのテストのようなものとして使用できます。もちろん、まだ存在しないあらゆる種類のクラスを呼び出すため、失敗します。しかし、この時点で、必要なコンポーネントの概要がわかります。
その後、テストを通じて個々のコンポーネントのそれぞれを駆動でき、それを完了すると、受け入れテストにも合格するはずです。
ビジネスロジッククラスがまだ作成されていない場合、受け入れテストは、WASが作成したものに対してのみ完了でき、プログラムが実行するものについては完了できません。 TDDのアイデアの1つは、テストが失敗するようにテストを記述し、コードを記述し、すべてのテストに合格するかどうかを確認することです。ただし、これが機能するのは、作成したテストがビジネスレベルでプロジェクトの要件を定義している場合のみです。
テストで何を実行するかを決定する必要があります。
コードの作成が完了したときに通知するのがポイントです。この場合、テストで要件を完全に定義する必要があります。スタックホルダーを満足させるすべての受け入れ基準の列挙としてそれらを確認してください。
コードの品質に自信を与えることがポイントです。これにより、コードをリファクタリングして、コードが想定どおりに機能することを確認できます。この場合、内部の変更が同じ外部の振る舞いを示すように表示できるように、コンポーネント間のインターフェースのテストにさらに焦点を合わせる必要があります。
開発中に、開発者が古い要件を満たしていないこと、または新しい要件を満たしていることを確認するポイントです。この場合、スイートの速度が影響する可能性があります。開発者が頻繁にテストを実行できる非常にタイトなループがあり、既知の品質までの時間が非常に短い場合は、迅速に実行できるテストのみを含める必要があります。次に、これらのテストを異なるスイートに分割して、異なる時間に実行できます。エディターで、保存後、コミット時、ビルドと一緒に、ビルド後、毎週、継続的になど。
すでに用意されている受け入れテストを使用するだけで十分ですか、それとも追加の単体テストを開発する必要がありますか?
場合によります。これらの新しいテストを追加する意味は何ですか?どのような目標を目指していますか?受け入れテストは、追加情報、コードの信頼性、バグの特定に役立つ場合に役立ちます。あなたはこの部分のすべてに同意しないかもしれませんが、古いテストを維持することさえそれほど価値がないかもしれないと示唆するので、 (ほとんどの単体テストが無駄である理由 を見てください)。必要なものを決定し、それに対するテストアプローチを構築します。
「ユーザーインターフェイスを通じて実行されるプロジェクト全体の受け入れテスト」はスクリプト化できません。それらを自動化して継続的な統合を行うことはできません。
だからとにかくunistテストが必要です。
また、ほとんどの場合、「受け入れテスト」は制限ケース、例外などをテストしません。