web-dev-qa-db-ja.com

テスト駆動開発(TDD)のテストは常に単体テストですか?

これまでのところ、テスト主導型の開発について理解しています。これは、失敗した(赤の)単体テストがある場合にのみ、生産的なコードを記述できるようにするものです。これに基づいて、テスト駆動アプローチを他の形式のテストにも適用できるかどうかという疑問があります。

41
user1364368

TDDで必要なことは、失敗したテストを記述し、コードを変更して合格することだけです。

通常、「単体テスト」は小さくて高速で、コードの一部を分離してテストします。それらは高速なので、red/green/refactorループも高速になります。ただし、パーツを個別にテストするだけで問題があります。したがって、他のテストも必要です(統合、受け入れなど)。それでも同じ原則に従うことは良い習慣です。失敗したテストを記述し、コードを変更して機能させるようにします。通常は遅いため、red/green/refactorサイクルタイムに影響する可能性があることに注意してください。

27
David Arno

赤と緑のリファクタリングサイクルは、1つの非常に堅実な原則に基づいて構築されています。

成功と失敗の両方を確認したテストのみを信頼します。

はい、自動統合テストでも機能します。また、手動テスト。一体、それはカーバッテリーテスターで動作します。これは、テストをテストする方法です。

単体テストは、テストできる最小のものをカバーしていると考える人もいます。何人かはテストするのが速い何かを考えます。 TDDは赤緑のリファクタリングサイクル以上のものですが、その部分には非常に特定のテストセットがあります。変更のコレクションを送信する前に一度実行するのが理想的なテストではありません。変更を加えるたびに実行するテストです。私にとって、これらはあなたの単体テストです。

59
candied_orange

ただし、テスト駆動型のアプローチを他の形式のテストにも適用できるかどうか疑問に思っています。

はい、そしてこれを行うよく知られたアプローチは 行動主導の開発 です。 BDDの正式な仕様から生成されたテストは「ユニットテスト」と呼ばれる場合がありますが、通常、実際のTDDほど低レベルではなく、「受け入れテスト」という用語に適しています。

12
Doc Brown

これまでのところ、テスト駆動開発について理解しています。これは、失敗する(赤の)単体テストがある場合にのみ、生産的なコードを記述できるようにするものです。

いいえ。テストのメッセージを変更するために可能な限り単純なコードを書くことのみが許可されています。どのようなテストかについては何も述べていません。

実際には、まず受け入れ基準の失敗した(赤の)受け入れテストを作成することから始めます。より正確には、失敗する可能性のある最も単純な受け入れテストを作成します。その後、テストを実行し、テストが失敗するのを観察して、正しい理由で失敗することを確認します。次に、その受け入れ基準の機能のスライスに対して失敗する機能テストを作成します。ここでも、失敗する可能性のある最も単純な機能テストを作成し、実行して、失敗するのを観察し、正しい理由で失敗することを確認します。次に、失敗する可能性のある最も単純な単体テストである失敗した単体テストを記述し、実行して失敗を監視し、正しい理由で失敗することを確認します。

Now、エラーメッセージを変更する可能性のある最も単純な製品コードを記述します。テストを再度実行し、エラーメッセージが変更されていること、正しい方向に変更されていること、およびコードが正しい理由でメッセージを変更していることを確認します。 (理想的には、エラーメッセージは今では消えており、テストは成功するはずですが、多くの場合、テストを1回で通過させるのではなく、小さなステップでメッセージを変更することをお勧めします。それが理由です。テストフレームワークの開発者がエラーメッセージに多大な労力を費やす理由!)

ユニットテストに合格したら、テストの保護の下で本番コードをリファクタリングします。 (現時点では、受け入れテストと機能テストはまだ失敗していますが、単体テストでカバーされている個々のユニットのみをリファクタリングしているため、問題ありません。)

次に、次の単体テストを作成し、機能テストにも合格するまで上記を繰り返します。機能テストの保護下で、複数のユニットにわたってリファクタリングを実行できるようになりました。

この中間サイクルは、受け入れテストに合格するまで繰り返されます。この時点で、システム全体でリファクタリングを実行できます。

ここで、次の受け入れ基準を選択すると、外側のサイクルが再び始まります。

TDDの「発見者」であるケントベック(「発明者」という用語は好きではありません。人々はこれをずっと続けてきたと彼は言います。彼はそれに名前を付けてそれについて本を書いただけです)は写真からの類推を使用し、これを「ズームインとズームアウト」と呼びます。

注:必ずしも3つのレベルのテストが必要なわけではありません。たぶん、時にはもっと必要になるでしょう。多くの場合、必要な数は少なくなります。機能の一部が小さく、機能テストが高速である場合は、単体テストなしで(または単体テストを少なくして)成功できます。多くの場合、必要なのは受け入れテストと単体テストだけです。または、受け入れ基準がきめ細かく、受け入れテストare機能テスト。

ケントベック氏によると、機能テストが小さく、小さく集中している場合は、最初にユニットテストを記述し、ユニットテストでコードを実行し、次に、そのコードをカバーするユニットテスト(の一部)を再度削除します。高速機能テストでカバーされています。覚えておいてください:テストコードは、保守とリファクタリングが必要なコードでもあります。

ただし、テスト駆動型アプローチを他の形式のテストにも適用できるかどうか疑問に思っています。

テストにTDDを実際に適用するわけではありません。開発プロセス全体に適用します。それがテストの「駆動」部分です---駆動-開発の意味:すべて開発はテストによって駆動されます。テストは、作成したコードを駆動するだけでなく、what書き込むコード、次に書き込むコードも駆動します。彼らはあなたのデザインを推進します。彼らはあなたが終わったときにあなたに言います。彼らはあなたに次に取り組むべきことを教えてくれます。彼らはあなたのコードの設計上の欠陥について教えてくれます(テストを書くのが難しいとき)。

キース・ブレイスウェイトは、彼が呼び出すエクササイズを作成しました TDD As You You Meant It これは、厳密に従う必要があり、TDDをより厳密に適用するように設計されている一連のルール( (ボブマーティンおじさんのTDDの3つのルール に基づいていますが、はるかに厳しい)で構成されています。ペアプログラミング(ペアがルールに違反していないことを確認できるようにするため)とインストラクターとの組み合わせが最適です。

ルールは次のとおりです。

  1. 正確に1つの新しいテストを記述します。これは、解決策の方向を示すと思われる、できる限り小さいテストです。
  2. それが失敗するのを見てください。コンパイルの失敗は失敗としてカウントされます
  3. (1)パスからテストを作成しますテストメソッド内で可能な最小の実装コードを記述します。
  4. 重複を取り除くためにリファクタリングし、そうでなければ、デザインを改善するために必要に応じて。これらの動きの使用については厳しくしてください:
    1. 新しいメソッドが必要です。リファクタリングの時間まで待ってから、…これらのいずれかを実行して、新しい(非テスト)メソッドを作成します。 :
      • 推奨:(3)に従って作成された実装コードに対してExtractメソッドを実行して、テストクラスに新しいメソッドを作成する、または
      • 必要な場合:(3)に従って実装コードを既存の実装メソッドに移動する
    2. 新しいクラスが必要です—リファクタリング時間まで待ってから、…移動メソッドの宛先を提供するために、他の理由なしに非テストクラスを作成します
    3. 他の方法ではなく、Move Methodを実行して、実装クラスにメソッドを入力します。

これらのルールは、TDDを実行するためのものです。実際にTDDを実行するためのものではありません(ただし、実際にTDDを試すことを妨げるものはありません)。実際に進歩せずに何千もの小さな小さなステップを踏んでいるかのように見えることがあるので、彼らはイライラするかもしれません。

8
Jörg W Mittag

TDDは、従来のソフトウェアテストコミュニティが「ユニットテスト」と呼ぶものにまったく限定されません。この非常によくある誤解は、ケントベックがTDDの実践を説明する際に「ユニット」という用語を不幸に過負荷にした結果です。彼が「単体テスト」で意味したのは、分離して実行されるテストです。他のテストに依存していません。各テストでは、必要な状態を設定し、完了時にクリーンアップを実行する必要があります。この意味で、TDDの意味でのユニットテストはユニットです。それは自己完結型です。単体で実行することも、他の単体テストと一緒に任意の順序で実行することもできます。

参照:「例によるテスト駆動開発」、Kent Beck著

ケントベックは、32章の「単体テスト」で彼が何を意味するのかを説明します-TDDの習得

2

私はそれに関する本を読んだこともないし、常に「標準」のTDDプラクティスに完全に従うこともありませんが、私の心では、TDDの哲学の主要なポイントは、私が完全に同意し、最初に成功を定義する必要があるということです。 。これは、「このプロジェクトの目標は何ですか?」から、デザインのすべてのレベルで重要です。 「この小さなメソッドの入力と出力はどうあるべきか?」

この成功の定義を行う方法はたくさんあります。特に、エッジケースが多くなる可能性のある低レベルのメソッドで役立つのは、コードでテストを記述することです。抽象化のレベルによっては、モジュールの目的などについて簡単なメモを書くか、精神的に自分自身をチェックする(または同僚に尋ねる)だけで、すべてが理にかなっていて、論理的な場所。統合テストをコードで説明すると便利な場合があります(もちろん、自動化に役立ちます)。また、すべてのシステムが連携して機能することを確認するために使用できる合理的なクイックテスト計画を定義するだけで役立つ場合もあります。期待しています。

しかし、あなたが使用している特定のテクニックやツールに関係なく、私の頭の中でTDDの哲学から取り除く重要なことは、成功を定義することが最初に起こるということです。それ以外の場合は、ダーツを投げて、着陸した場所のどこにでもブルズアイをペイントします。

1
user101289

講演では テスト駆動開発:これは私たちが意図したものではありません スティーブフリーマンは、TDD全体像の次のスライドを示します(回答の下の画像を参照)。これには、ステップ「失敗するエンドツーエンドテストの作成」が含まれ、その後に「失敗するユニットテストの作成」が続きます。 (クリックして拡大すると、右上に表示されます)

したがって、TDDでは、テストは必ずしも単体テストではありません。

そして、はい、最初の単体テストを作成する前に失敗する、より高レベルのエンドツーエンドのテストから始めることができます(おそらくそうする必要があります)。このテストは、達成したい動作を記述します。 test-pyramid のより多くのレベルでカバレッジを生成します。エイドリアン・サットンはLMAXの経験について説明します エンドツーエンドのテストが大きくて価値のある役割を果たすことができることを示しています

enter image description here