web-dev-qa-db-ja.com

アジャイルが開発主導型テスト(DDT)ではなく、テスト主導型開発(TDD)にすべて関わっているのはなぜですか?

だから私はアジャイルは初めてですが、 テスト駆動開発 ではありません。大学の教授たちは、テスト、コード、そしてテストのアイデアを中心に考えていました。理由がわかりません。私の観点からすると、コードの進化に伴って変更される可能性が高いのは、多くの先行費用です。

これが私がTDDを想像する方法であり、それが私を混乱させる理由です。 TDDの請負業者として家を建てる場合。

  1. すべての仕様(ストーリー)を教えてください。

  2. 仕様の承認を得る。

  3. すべての仕様を、私が必要と思う検査に分解します(将来的に参照)。

  4. 査察官に電話してこれらの点を確認し、今すぐ検査に不合格になっていることを伝えてください(ありがとう)。

  5. 家を建て始めます。

  6. 検査官に毎日電話をかけます(2/100を通過)。

  7. ああ、私の理解に問題があり、9個の検査を追加して27個を変更する必要があります。

  8. 1/109に合格したインスペクタを呼び出します。

  9. 畜生。インスペクターがこのようにしないのはなぜですか...ああ、そのメソッド名を更新しました...

  10. さらにビルドします。

  11. UGGGGHHHHその他の変更により、いまいましいインスペクタを更新できます。ああ、私は失敗していません。

  12. もう終わった?

さて、それは風変わりかもしれませんが、私のコードがそこにあるまで、私がすべてのメソッドをどのように知るべきか、そしてどのように機能するかを知りません。 99%戻ってユニットテストを更新し、必要に応じてさらに追加する必要があります。それはただ逆に思えます。

より適切と思われるのは、DDTまたは開発主導のテストです。これは、コミュニティーがすべて忘れてしまっているようです。

私の理解では、家のDDTは次のようになります。

  1. すべての仕様(ストーリー)を教えてください。

  2. 仕様の承認を得て、それを打ち破ってください。

  3. ユニット(基礎)を開始します。

  4. いくつかのトリッキーなロジックのメモ(コメント)を取ります。

  5. 最後に、次のユニットを開始する前に検査を行います(テストを作成します)。

  6. 見つかった問題を修正し、再度検査します。

  7. このユニットが次に移動することを承認しました。

もし私たち全員が正直であるならば、それはもっと人間に聞こえ、開発者とビジネスに集中していませんか?変更をより速く行うことができ、オーバーヘッドなしでTDDが作成するようです。

74
nerdlyist

TDDアプローチの利点の1つは、新しい設計も行う場合にのみ実現されます。

したがって、最初のアナロジーでは、ソフトウェアがどのように見えるかを知ることができないため、100回のテストを記述しません。

あなたは1つのテストを書きます。あなたはそれを実行します。それは失敗します。テストに合格するには、コードの最小単位を記述します。次に、テストを再度実行します。合格です。

次に、上記のプロセスを繰り返して、次のテストを記述します。

これは、コードの目的が明らかな当初は無駄なアプローチのように思えるかもしれませんが、このアプローチの優れた点は、テストカバレッジが常に高く、コード設計がこのようにすっきりしていることです。

方法としては、ペアプログラミングと密接に関連しています。 1つのペアがテストを記述し、次のペアがコードを記述して合格とし、次に次のテストを記述します。

私は新しいクラスを書くときにもこのアプローチを使用しています。最初のテストは、クラスコンストラクターを開始する呼び出しです。しかし、まだクラスを作成していないため、失敗します。次に、単純な空のクラスを記述して、最初のテストに合格します。

いったん考え方に入ると、その中にいなくて「昔ながらの」方法でコーディングすることは非常に困難です。

これを学ぶには、優れたアジャイル環境で作業するか、理解を深めるためにいくつかの優れたアジャイルブック(Clean CodeとClean Coderはどちらも非常に優れています)を読むことをお勧めします。

83
Phil Riley

ソフトウェアは家ではありません。直感は良いですが、常に正しいとは限らないことを理解してください。

すべての仕様を、私が必要と思う検査に分解します(将来的に参照)。

これは正確ではありません。 TDDでは、コードの使用方法を記述しています。仕様には、「そこに入る方法がある家がなければならない」と書かれています。次に、テストは「ねえ、ノブの付いた正面玄関が欲しい」と言います。これはfarドアフレーム、ノブ、キーロックなどの構築の実装から始めるよりも、将来を見通すことが少なくなります(または、そのため、議論は進みます)。

検査官に毎日電話をかけます(2/100を通過)。

これは正しくありません。あなたは家のテストを書いているのではありません。あなたはフロントドアフレームのテストを書いていて、それからそれらをグリーンにします。次に、ドアがしっかりしていることをテストし、ドアを緑色にします。 たぶんダース程度のテストが常に与えられているはずです。通常、それは2〜4に近いです。

また、「査察官に電話をかける」という類推は、その人が出て仕事をするのにある程度の時間がかかることを意味します。 TDD反復の単体テストの実行には、文字通り数秒かかります。

変更はより速く行うことができ、オーバーヘッドなしでTDDが作成するように見えます。

オーバーヘッドはあなたが示唆しているように見えるよりも少ないです。テストを実行するための数秒は、おそらく半ダース回は、全体的な開発時間には重要ではありません。

最初にdevの問題は、テストに到達したときにbig問題があることがわかります。あなたがトイレの隣にベッドを置いたように、誰もそこにある種の問題に住みたいとは思わない。どのようなTDDオーバーヘッドよりも修正に時間がかかるもの。 TDDはコードを最初から使用し、それとのインターフェース方法を考えることを強制するため、TDDがキャッチしたことになります。

私の大学の教授たちは、テスト、コード、そしてテストのアイデアにすべて興味を持っていました。

とはいえ、TDDはそれほど普及しているわけではありません。多くの場所がまだ開発を先に行っており、TDDの利点の多くは誇張されています。重要なのは、テストを作成し、それを優れたものにすることです。作業を行う順序はそれほど重要ではありません。

86
Telastyn

物理的なものを作成することとソフトウェアを書くことの類似点はごくわずかです。

とはいえ、指摘する価値のある大きな違いが1つあります。

「テストの作成」と「テストの実行」には違いがあります

家を建てる例では、要件とテストdoが実際の建築の前に行われます。そして、テストスイートの一部が継続的に-複数のエージェントによって実行されます!ビルダーが2x4を拾ったとき、彼は「自動的に2x4のサウンドがどのように見えるか」という概念に対してユニットを「自動的に」テストします。彼はそれを取り上げた後、要件を作成しません。彼は既存のチェックを実行します。

同様に、組み立てられた壁、電気ボックス、配管などの場合-テスト/要件はすでに存在しています。彼らは暗黙のうちにそして自動的に仕事の全員の訓練された目によって継続的に実行されます。インスペクターが訪問すると、既存のテストの別のスイートが実行されます。ユニットがそれらのpre-existentテストに合格するように構築されていない場合、ユニットは失敗します。

構造全体についても同様です。計画はビルドアウト前から存在しています。エンジニアはすべての段階で、ビルドアウトの完了時に構造が最終的にテストされるとなる既存の条件セットに向けて取り組んでいます。

とはいえ、すべての物理プロジェクトの前に巨大な一連のテストを行う必要はありません。ワークショップに行って、おもちゃ箱などのために木材を組み立て始めたら、直感と創造性があなたを導き、それは厳密なTDD木工ではありません。その場合、基本的には媒体の物理的な法則と、作品を検証するための大まかな期待に依存しています(つまり、「コンパイルして機能する場合、それは良いことです!」)。

そして、それは大丈夫です。すべての前に厳密なテストを行う必要はありません。

tl; dr

構文!=書き込みソフトウェアですが、構文はテスト駆動方式で動作します。すべてのユニットの「合格」条件doがビルドアウトに先行します。

「テストの実行」と「テストの作成」を混同しないでください。

すべてがTDDである必要はありません。

13
svidgen

あなたは、ソフトウェアを書くことは家を建てることに似ているというナンセンスな考えを信じるという罠に陥りました。そうではありません。これは、建築家の図面や構造エンジニアの計算を作成することに似ています。

今では実際の家があり、建築家はそれらの計画を前もって作成します。次に、ビルダーを呼び出します。ビルダーは、構築を開始し、問題に遭遇し、物事を修正し、建物の管理を取得し、変更を希望します。その後、最後に、建築家が戻ってきて、図面を更新して反映するように請求します。どうした。これは物足りないやり方ですが、家を建てるには長い時間がかかり、費用もかかるため、これが唯一の実用的な方法です。

ソフトウェアエンジニアリングには物事が優れています。家を建てるのと同じことは、コンパイラーにコードをある種のコンパイル済みユニット(ライブラリー、アプリ、Webアプリなど)に変換させることです。これを1日に数百回実行するのは非常に高速で安価です。その結果、機能を追加するときに家を繰り返し再構築することは意味がなく、最後にインスペクター(QA)を呼び出してテストするだけです。代わりに、これらのチェックを自動化すると、再構築するたびにインスペクターにすべてを再検査させることができます。

厳密なTDDに従うか、それともtest-orientatedの方法でコードを記述してからテストを行うかは、実際には重要ではありません。私は最初のアプローチを好み、他のアプローチは後者を好みます。あなたに合ったものを選んでください。重要なことは、これらのチェックを作成しながら作成することです。これらは、何かを変更したときに他の場所で機能が停止することを警告することで、後でコードを変更したいときに役立ちます。

11
David Arno

まず第一に初期費用はあなたが思っているほど高くありません。はい、テストを行わない場合よりも、テストへの対応に多くの時間を費やしています。しかし、「テスト後」の方法を実行すると、本当に何を無駄にしているのでしょうか。 TDDに10時間、DDTに6時間かかるとします。 「追加」の先行費用はわずか4時間です。 90%のカバレッジなどのコードメトリックまたは要件を適用すると、TDDとDDTのコストがさらに近くなります。

TDDを使用すると、バグの少ないコードを書くことができます。テストとして要件を詳しく説明したからといって、1日の終わりに、コードが実行していることを証明できます。まさにあなたが望んでいたこと。たぶん、あなたはそれが間違ったことをしたいと思ったかもしれませんが、それは変更要求であるバグではありません。これは重要。機能している製品を「販売」する方が簡単ですが、機能が異なる/優れている場合は、機能していないと認識されている製品を販売します。 TDDでは、テストに合格して機能しないコードを記述することは文字通り不可能です。要件を理解していない可能性があり、間違ったが機能するコードを記述した可能性があります。

TDDはコードベースが古いほど良いです。テストスイートなしで、または不十分に実装されたテストスイートでリファクタリングしてみてください。単純な変更でもバグが発生する可能性があります。適切なカバレッジのテストスイートを用意することで、製品が進化しても、期待どおりに機能し続けることが保証されます。また、競合するビジネスルール(長期間にわたって発生する)を強調表示するのにも役立ちます。

機能しないことはわかりません。テストスイートがないと、コードが思ったとおりに機能しているかどうか、またはコードが正しく機能しているように見えるかどうかがわかりません。ワーキング。

_var foo = function(in) {
    if(in == 0) {
      return true
    }
}
_

アプリケーション全体でif(foo()){ doStuff() }を呼び出します。fooを修正するとどうなりますか?

_var foo = function(in) {
    if(in === 0) {
      return true
    }
}
_

あなたはリファクタリングしているべきです DRYing あなたのテストも。良いテストスイートは維持するのが難しくありません。うまく記述されたアトミックテストを使用すると、一度に戻ってそれらを1〜2以上変更する必要はほとんどありませんでした。テストスイートに大きな変更があった場合、それは何かが正しくないことを示す大きな赤旗です。

私のすべてのメソッドをどのように知る必要があるのか​​、そしてコードがそこにあるまではどのように機能するのかわかりません。

まあ、あなたはそうではありません。ある作業単位が完了したことをテストするテストを書くことになっています。あなたがおそらく知ることができないことをテストしているように感じたら、あなたは大きすぎると考えています、ORテストが小さすぎます。

たとえば、ドアが閉まり、ロックされることを知る必要があります。私はdoor.close()とdoor.lock()をテストし、ドアがロックされていると、door.open()がfalseを返します。それだ。テストがdoor.lock()の場合、データベースにフラグを設定します。次に、テストが小さすぎます。テストはdoor.lock()がどのように機能するかを知る必要はありません。

ここで、すべてのドアと窓がロックされているときにhouse.isSecure()がtrueを返すというテストを記述している場合。最初にドアや窓を見ないでいると、あなたは大きすぎると考えています。

最後に、あなたは大きすぎる仕事の単位を見ているかもしれません。要件のリストを取得したら、最小単位で作業できるように整理する必要があります。そのユニットだけのテストを記述してから、コードを記述し、すすぎ、繰り返します。

本質的に、TDDがどのように機能するかについての理解(リスト)は無効です。 2/100をパスすることはできません。 1/1パス、2/2パス、3/3パス、4/4パスのようになります。

あなたのための改訂リスト

  1. すべての仕様を入手する
  2. 仕様を1つ選択してください
  3. 試して
  4. コーディングする
  5. 試して
  6. テストに合格した場合は7に進み、そうでない場合は4に進みます。
  7. すべての仕様を完了したら、8に進みます。それ以外は2に進みます。
  8. 消費者と仕様を確認し、必要に応じて新しい仕様を追加します。正しく行われれば、テストをまったく変更する必要はありません。新しいものを追加するだけです。要件の収集がバラバラになり、以前のテストと競合するテストを追加する必要がある場合がありますが、テストを変更する必要はほとんどありません。
7
coteyr

他の答えが欠けていると感じるいくつかの鍵があります。

つの利点

まず、エラーのコストと変更のコストは、ソフトウェアと家の間で信じられないほど異なるため、いくつかのルールが適用されない場合があります。たとえば、物理構造をテストするコストは非常に高いので、テストを無駄にしないように、それが機能するという高い信頼度が必要です。ソフトウェアを使用して、1〜5秒で一連の単体テストを実行できる場合は、さまざまなオプションを自由に使用できます。

次に、テスト対象コードを記述する前に失敗すると予想されるテストを実行する目的は、テスト自体を検証することです。確かにそれはばかげているか無駄に見えるかもしれません。しかし、テスト対象のコードが壊れている場合でも、常に合格する方法で記述された十分な単体テストを見てきました。これは、テスト対象のコードを作成し、手動でテストしてから、単体テストを作成するときに簡単に発生します。単体テストを作成する場合、失敗することを確認してから、テストを成功させるために必要なコードを作成してテストに合格すると、テストが適切であることがわかります。テスト対象のコードがリグレッションした場合、ユニットテストがそれをキャッチする合理的な可能性があります。

TDDの3番目の利点は、あまり言及されていませんが、結果として得られるコードのサイズと複雑さは、多くの場合、桁違いに小さいことです。私はいつも、シンプルで簡潔なコードを好むことに誇りを持っています。 TDDの練習を始めるまで。 TDDは、私が以前にやっていることは過度のコードであることを示しました。なぜこれが起こるのですか?テストを作成するので、テストに合格するためのコードを作成します。テストに合格すると、テストは完了です。この考え方に慣れている場合は、誤って「余分な」コードを書くことは困難です。

(私が以前使用していた製品で私が観察した問題は、余分なコードでした。誰も求めなかったが、一部の開発者はそれがクールだと思ったコードに起因する重大な問題です。)

コスト分析

ですから、ある意味では、あなたは正しいです。家を建てるとき、私たちはこの戦略を回避できませんでした。それは高すぎるでしょう。しかし、ソフトウェアは家ではありません。ソフトウェアは安いです。

家との類似は、家を組み立てる労力対ソフトウェアコンパイラです。

非TDDの世界では、開発者はまだ繰り返します。コード->コンパイル->実行->テストサイクルに従います。私たちはすでに家を建てることから大きく逸脱したモデルにいます。建設担当者がドアフレームを作成してからドアを作成し、ドアが大きすぎるためにフレームを再作成する必要がある場合、コストの問題が発生します。したがって、すべてを完璧にするために、前もって多くの時間を費やします。プログラミングでは、ほとんどのプロジェクトは数秒または数分でコンパイルできるため、何かが不完全であっても問題ありません。事前に些細なことを考えるコストは、通常、再コンパイルのコストを上回ります。したがって、常に再コンパイルします。

TDDは同じ原理であり、テストを前に進めるために回転させます。テストを非常に安価に(すべてを数秒で実行できるように)できる場合、単一のビッグバンコーディングの反復で全体像、完全、全体的なソリューションを検討するコストは、リファクタリングのコストを上回ります。

除く...

これらの引数が成り立たないプログラミングにはいくつかのことがあります。それが建築の目的です。後で変更するにはコストがかかるであろう事前の懸念事項を特定して計画します。たとえば、ニーズを考慮せずにその場でデータベースを選択し、構築を開始して、後で変更できると主張することはありません。あなたはそれをじっくりと考える必要があります。

4
Brandon

この質問にはすでに受け入れられた回答がありますが、筆記テストではないデザインスタイル(テスト手順に従って「テスター」が手動で実行したすべてのテスト)からTDDに追加する必要があると思います。これらは私の個人的な見解ですが、かなり普遍的なものだと思います。

新しい何かを書いたり、これまでに行ったことのない何かを書いたりする場合、TDDを行うことと行わないことの間に大きな違いはありません。

一般的には、小さなコードを書いてアイデアを探索し、ハードコードされたビットを追加して「テスト」してから、コンパイルまたは実行します。それが機能する場合は、ハードコードされたものを削除し、パラメーター、インスタンス変数などを追加してコードを一般化します。

それについて考えてください。これは、TDDとまったく同じ作業量です。唯一の違いは、TDDで「テスト」ビットを個別に別のファイルに書き込み、最後にそれらを削除しないことです。 TDDではテストコードを保持します

もちろん、TDDが少し整理されているということは、コードのテストビットを実際のコードから分離する方法を理解するためにもう少し作業が必要であることを意味します。ただし、ユニットテストを作成したことがある場合は、テスト用にコードをモジュール化する方法を学習します。

4
slebetman

TDDのいくつかのプロジェクトを行うまで、私はこれについてよく考えていました。私がこれをしている間に私に飛びついた非常に簡潔で包括的な説明があります:

コードを書くときは、コードが意味のあることを確実に行うための何らかの方法が必要です。コードをテストします。アドホックテストを実行できます。ただし、物事を始める前にテストする方法を考えれば、テストはうまく機能します。したがって、テストに進む前にテスト戦略を設計します。

テスト戦略について考えているので、少なくともその一部を自動化することをお勧めします。そして、ある程度のTDDがあることに注目してください。テストに合格するまでコードを作成するのはごく普通のことです。それはとにかくあなたがやっていることです、それが機能するまでコードを書きます。テストを爆破するのは今や簡単です。

範囲外の理由で、一度にすべてを書くことはしません。したがって、テストを一度に設計することもありません。しかし、基本的にはそれがそうです。テストの計画を改善するだけで、常にテストを前もって作成するわけではありません。進行中に予期しないバグを見つけたり、後でテストをより堅牢にするために、さらに追加することがあります。また、テストを設計していなくても、後で手動でテストするのは面倒なので、後でテストを行う場合もあります。

したがって、TDDは、作業を検証する方法を検討するための極端な方法にすぎません。

4
joojaa

アジャイルが開発主導型テスト(DDT)ではなく、テスト主導型開発(TDD)にすべて関係するのはなぜですか?

この質問は、私がかなり不快であると思う事実(「アジャイルはTDDに関するすべて」)を示唆していることがわかったので、ここで声を上げています。すべての回答は、この事実を当然のことと考えているようです。アジャイルが主にTDD(別名、ユニットレベルでのテスト)に関するものであると想定する場合、これらは良い答えです。

https://en.wikipedia.org/wiki/Agile_software_development#Agile_methods は、多数の異なる開発モデルをリストしています。

特に振る舞い主導の開発と機能主導の開発は、思考の糧として提供します。 完全に異なる獣は、基本的なTDDのすべての利点をもたらすことができますが、単純な赤-緑-リファクタリングサイクルとはかけ離れています。

だから私の答えは:

  • 「DDT」(別名、または実装の「上」にテストを記述する)は、実際の理由では機能しません。あなたが時間やお金のプレッシャーを得るとすぐに、テストは窓の外に出ます。とにかく、テストを実施するためにテストを実施することは、どちらかと言えばIMOです。
  • アジャイルはではないテスト駆動開発(TDD)に関するすべてのことを基本的に「すべてのビルディングブロック/クラスのユニットテスト」(これは、 、少なくともウィキペディアによればそうです)。 TDDは、アジャイル開発を行うための1つの可能性にすぎません。
  • BDDやFDDなど、フルスタックアプローチを行う他の方法があります。シナリオを前もって作成し、赤と緑のリファクタリングサイクルがあり、シナリオが緑になるまで実装するだけですが、「テスト」は定義上、ソフトウェア全体を(ユーザーの操作のように動作させることによって)実行し、決して実行しません。 1つのユニットのみ。

完全なBDD/FDDカバレッジとユニットテストがないアプリケーションよりも、完全なユニットテストカバレッジとフルスタックテストがないアプリケーションが欲しいです。

(TDDはもちろんAPIなどにその場所がありますが、ここではそれについて話していません。)

繰り返しになりますが、ここでは他のすべての回答をダウントークするつもりはありません。質問はかなり狭く定式化されており、フィールドには提供できることはもっとたくさんあることを指摘しているだけです。

2
AnoE

このように頻繁に記述されていることはありませんが、アジャイルの背後にある理由の多くは、コードを最初から上手に書くよりもコードを書き直す方が良いということです。コードを書き直すたびに、コードを改善し、自分自身を改善します。初めて「正しい」ものにすることは、遅くなり、よりもろくなる傾向があります。

家のアナロジーはそれほど悪くはありませんが、家の建設について私たちが知っている期間とソフトウェアエンジニアリングについて私たちが知っている期間について考える必要があります。また、ソフトウェアエンジニアリングの複雑さは、長い橋の建設に近いですまたは家より20階建ての塔。また、新しい言語とツールが構築されると、それはすべてのビルダーが完全に異なる形状、サイズ、材料で建物を構築したいと思ったようなものであることも考慮する必要があります。完全な混乱。

ただし、検査はコードテストとよく似ていません。ソフトウェアでは、適切なインスペクターがいるほどではありません(さまざまなスキルレベルの同僚を除く)。また、おそらくほとんど任意の「コーディング標準」(構造よりもペイントの色と芝生のレイアウトをテストするようなもの)を除いて、検査する規制もありません。

テストファーストは、壁を構築するようなものです。壁を持ち上げて家に置く前に、壁に圧力をかけて安定性を確保します。これは、窓を配置する前に、窓を測定して、残した穴に収まることを確認するようなものです。

何世紀にもわたるアーキテクチャの知識、パターン、規制、および数学を使用せずに一連のブリッジを構築しなければならなかった場合、ブリッジを構築する前にブリッジが機能することを証明する必要がある場合は、LOTでブリッジをテストして再構築することになります。

最後に、非分析ポイント-コードのセクションを書き換えることができるたびにソフトウェアを使用すると、コードとスキルの両方が大幅に向上します。可能な限り、コードを書き直してください。 TDDは大きな言い訳になり得ます。

0
Bill K