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


41

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


6
互いにネストされた複数の異なるレベルの赤/緑/リファクタリングを使用することは珍しくありません。たとえば、受け入れ/動作テストの記述中に赤/緑/リファクタリングを実行できます。受け入れテスト自体の「緑」フェーズには、ユニットテストの複数の赤/緑/リファクタリングの反復が含まれます。
ショーンバートン

1
タイトルが質問の内容と一致しません。タイトルは「テストは常にユニットテストです」(答え:いいえ、ユニットテスト以外のタイプのテストも可能です)、コンテンツは「最初にテストを書く必要がありますか?」と尋ねます。
AnoE

@AnoEコンテンツの最初の文は単なる紹介文です。seconds文は、テストを最初に記述する必要があるかどうかを尋ねませんが、TDDアプローチをTDD以外のテストメソッドに使用できるかどうかを尋ねます。
user1364368

@ user1364368、質問を少し自由に再編成してください。少なくともあなたの意図が最初の読書で何であるかについて混乱しました、そして、あなたの両方の文章に対処することも最初の質問で顕著である一方で、トップ投票の質問です。
AnoE

@AnoE実際の質問が何であるかを明確にするために、2番目の文の先頭を変更しました。
user1364368

回答:


27

TDDに必要なのは、失敗したテストを作成し、コードを修正して合格することだけです。

通常、「ユニットテスト」は小さくて高速であり、コードの一部を単独でテストします。これらは高速であるため、赤/緑/リファクタリングループも高速になります。ただし、テストするのは部品の分離だけです。そのため、他のテスト(統合、受け入れなど)も必要です。同じ原則に従うことをお勧めします。失敗したテストを作成し、コードを修正して動作するようにします。通常は遅いため、赤/緑/リファクタリングのサイクルタイムに影響する可能性があることに注意してください。


59

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

合格と不合格の両方を確認したテストのみを信頼してください。

はい、自動化された統合テストでも機能します。手動テストも。まあ、それは車のバッテリーテスターで動作します。これがテストのテスト方法です。

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


1
これは、エラーが発生したことをテストするときに負のテストが重要である理由の1つでもあります。互いに助け合うことで、将来この赤/緑の状態が続くという自信を高めることができます。
マチューM.17年

12

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

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


8

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

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

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

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

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

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

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

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

TDDの「発見者」であるケント・ベック(彼は「発明者」という言葉が好きではない、彼は人々がずっとこれをやってきたと言い、名前をつけてそれについて本を書いた)これを「ズームインおよびズームアウト」と呼びます。

注:3つのレベルのテストが常に必要なわけではありません。たぶん、時にはもっと必要なことがあります。多くの場合、必要なものは少なくなります。機能の一部が小さく、機能テストが高速な場合は、なしで(またはより少ない単体テストで)うまくいくことができます。多くの場合、受け入れテストと単体テストのみが必要です。または、受け入れ基準が非常にきめ細かいため、受け入れテスト機能テストです。

Kent Beck氏によると、高速で、小さく、焦点を絞った機能テストがある場合、まずユニットテストを記述し、ユニットテストにコードを駆動させ、次にコードをカバーするユニットテスト(の一部)を再度削除します。高速機能テストでカバーされています。覚えておいてください:テストコードは、メンテナンスとリファクタリングが必要なコードでもあり、少ないほど良いです!

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

TDDを実際にテストに適用するわけではありません。開発プロセス全体に適用します。これは、試験-の一部が「駆動」何ドリブン開発-手段:すべてのあなたの開発はテストによって駆動されます。テストは、あなたが書くコードを駆動するだけでなく、どのコードを書くか、次にどのコードを書くかを駆動ます。彼らはあなたのデザインを推進します。完了したら、彼らはあなたに伝えます。彼らは次に何をすべきかを教えてくれます。彼らはあなたのコードの設計上の欠陥について教えてくれます(テストを書くのが難しいとき)。

Keith Braithwaiteは、TDD As As You You Meant Itと呼ぶエクササイズを作成しました。これは一連のルールで構成されており(ボブ・マーティンおじさんのTDDの3つのルールに基づいていますが、より厳密です)、厳密に従う必要があり、TDDをより厳密に適用するように設計されています。ペアプログラミング(ペアがルールを破っていないことを確認できるようにする)とインストラクターが最適です。

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

  1. 新しいテストを1つだけ記述します。これは、ソリューションの方向を指していると思われる最小のテストです。
  2. それが失敗するのを見てください。コンパイルの失敗は失敗としてカウントされます
  3. testメソッドで可能な限り最小の実装コードを記述して、(1)パスからテストを作成します。
  4. 重複を除去するためにリファクタリングし、そうでなければ設計を改善するために必要に応じて。これらの動きの使用について厳しくしてください:
    1. 新しいメソッドが必要です。リファクタリングの時間まで待機してから、次のいずれかを実行して、新しい(テスト以外の)メソッドを作成します。
      • 推奨:テストクラスで新しいメソッドを作成するために、(3)に従って作成された実装コードでメソッドを抽出する、または
      • 必要な場合:(3)に従って実装コードを既存の実装メソッドに移動する
    2. 新しいクラスが必要です。リファクタリング時間まで待機してから、テスト以外のクラスを作成して、Moveメソッドの宛先を提供し、他の理由はありません
    3. Moveメソッドを実行して実装クラスにメソッドを設定します。他の方法は使用しません。

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


2

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

参照:「サンプルによるテスト駆動開発」、Kent Beck著

ケントベックは、第32章「TDDをマスターする」で「ユニットテスト」によって彼の意味を説明


1

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

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

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


1

トークでは、テスト駆動開発:これは、Steve FreemanがTDDの全体像の次のスライドを示すことを意味するものではありません(答えは下の画像を参照)。これには、「失敗したエンドツーエンドテストを書く」ステップの後に「失敗した単体テストを書くステップが含まれます。(クリックして拡大、右上にあります)

したがって、TDDでは、テストは常に単体テストであるとは限りません。

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

ここに画像の説明を入力してください


-1

いいえ、他の種類のテストは実行に時間がかかりすぎるという単純な実用上の理由から、他の種類のテストには適用できません。

典型的なTDDサイクルは、失敗したテストの作成、コードの実装、リファクタリングです。その間のステップはテストの構築と実行であり、これらは非常に高速である必要があります。そうでない場合、人々はステップをスキップし始め、それからあなたはもうTDDをしていません。


1
これは誤りです。プログラムとテスト(および言語)に応じて、エンドツーエンドの統合テストは3秒未満で簡単に実行できます。適切に設計されていても、完全なエンドツーエンドのテストスイートを非常に短い時間で実行することは完全に可能です。そのため、「できない」は非常に強力です。
ジョナサンキャスト

@jcastこんなに速いものは見たことがない。前のプロジェクトでの機能テストには30秒かかりましたが、それは高速です。統合はさらに長くなります。私の場合、それ以外の意味はありませんでした。また、単体テストはあらゆる種類のテストの中で最速です-したがって、それらを使用するのは理にかなっています。
BЈовић
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.