テスト駆動開発(TDD) は最近大きな問題です。プログラマーSEや他の場所での幅広い問題の解決策として推奨されることがよくあります。なぜうまくいくのかしら。
エンジニアリングの観点からは、2つの理由で私を困惑させます。
要約すると、私はTDDの「駆動」ビットの方が「テスト」ビットよりも心配しています。テストは完全にOKです。私が得られないのは、それを行うことでデザインを推進することです。
ソフトウェアエンジニアリングにおけるTDDが良い方法である理由、および上で説明した問題がソフトウェアの場合に関連しない(または十分に関連しない)理由を含む回答を参照してください。ありがとうございました。
ここには誤解があると思います。ソフトウェア設計では、設計は製品に非常に近いです。土木工学、建築では、設計は実際の製品から切り離されています。設計を保持する設計図があり、それが完成品に具体化され、膨大な時間と労力によって分離されます。
TDDは設計をテストしています。しかし、すべての車の設計と建物の設計もテストされています。建設技術が最初に計算され、次に小規模でテストされ、次に大規模でテストされてから、実際の建物に配置されます。たとえば、Hビームと荷重を発明したとき、これが試されたことを安心して、実際に最初の橋を架ける前にもう一度試してみました。
試作車を設計することで車の設計もテストされます。そして、確かに、それが期待に応えるまで、正確ではないものを調整することによってテストされます。ただし、このプロセスの一部は遅くなります。なぜなら、あなたが言ったように、製品をあまりいじることができないからです。しかし、車のすべての再設計は、以前の車から学んだ経験を利用しており、すべての建物には、空間、光、断熱材、強度などの重要性について、その背後にある何十年にも及ぶ基礎があります。詳細は、建物の両方で変更および改善されていますそして、新しいもののための再設計。
また、パーツもテストされます。おそらくソフトウェアとまったく同じスタイルではないかもしれませんが、機械部品(ホイール、イグナイター、ケーブル)は通常、測定され、サイズが正しいこと、異常が見られないことなどを確認するためにストレスが加えられます。測定され、レンガをタップして壊れたものを見つけたり、実際に構成やその他の方法でテストされたり、大きなグループの限られた表現を描画して実際にテストしたりします。
これらは、TDDを使用して配置できるすべてのものです。
実際、テストは保証ではありません。プログラムがクラッシュし、車が故障し、風が吹くと建物が面白いことを始めます。しかし...「安全性」は真の問題ではありません。あなたがすべてを含めることができないときでさえ、カバーすることができます-例えば-偶然性の99%は50%だけをカバーするよりも優れています。テストを行わずに鋼を見つけることはうまく解決できず、もろくなっていて、主な構造物を立てるだけのハンマーの最初の打撃で壊れてしまい、金の無駄遣いになります。まだ建物を傷つけるかもしれない他の懸念があるということは、簡単に防止可能な欠陥があなたのデザインを落とすことを許すためにそれをそれほど愚かにしないことではありません。
TDDの実践に関しては、それはバランスの問題です。別の方法で実行する場合のコストに対する、一方の方法で実行する場合のコスト(たとえば、テストせずに、後で断片を取得するなど)。それは常にバランスです。ただし、他の設計プロセスにテストとTDDが用意されていないと考えないでください。
IMO、TDDのサクセスストーリーのほとんどは偽物であり、マーケティングの目的にすぎません。それで成功することはほとんどないかもしれませんが、小さなアプリケーションでのみです。 TDDの原則が使用されている大きなSilverlightアプリケーションに取り組んでいます。アプリケーションには何百ものテストがありましたが、まだ安定していません。複雑なユーザー操作のため、アプリケーションのいくつかの部分はテストできません。多くのモックとコードを理解することが難しい結果のテスト。
最初はTDDを試しましたが、すべて問題ないようです。たくさんのテストを書いて、単体テストが難しい部分を模擬することができました。かなりの量のコードがあり、インターフェースの変更が必要になると、ねじ込まれます。多くのテストを修正する必要があり、コードの実際の変更よりも多くのテストを書き直します。
Peter Norvigは、Coders At Workの本でTDDに関する彼の見解を説明しています。
ザイベル:テストを使用して設計を推進するという考えはどうですか?
Norvig:私はテストを、設計の方法というよりは、エラーを修正する方法として捉えています。 「まあ、最初に行うことは、最後に正しい答えが得られると言うテストを書くことです」というこの極端なアプローチは、それを実行して、失敗することを確認してから、「どうしますか?次に必要ですか?」—それは私にとって何かを設計する正しい方法のようには思えません。ソリューションが事前に定義されているほど簡単だった場合にのみ、そのように思えます。最初にそれについて考える必要があると思います。あなたは言う必要があります。一部が何であるかがわかるまで、どのようにしてピースのテストを書くことができますか?」そして、それが終わったら、それらの各部分についてテストを行い、それらが相互にどのように相互作用するか、境界ケースなどをよく理解することは良い分野です。それらすべてにテストが必要です。しかし、「このテストは失敗しました」と言って設計全体を推進するとは思わない。
テスト駆動設計は、次の理由で機能します。
これは、テストケースから確認できることを意味します。
多くの場合、コードはfirstで問題を解決し、次に記述したコードがどのように呼び出されるかを考える方法で記述されます。これは、「フラグを追加する」などの方が簡単なため、扱いにくいインターフェイスになることがよくあります。「テストケースがそのように見えるように、これを行う必要がある」と考えることで、これを裏返します。これにより、コードが呼び出しインターフェースに基づいて記述されるため、逆ではなく、モジュール性が向上します。
これは通常、説明が少ないドキュメントを必要とするよりクリーンなコードにもなります。
実行可能なフォームの仕様があるので、完全なテストスイートに合格すると完了です。より詳細なレベルで物事を明確にすると、さらにテストを追加できますが、基本原則として、進行状況と完了時の非常に明確で目に見える指標があります。
これは、作業が必要かどうかを判断できることを意味します(テストに合格するのに役立ちます)。
それについて熟考している人にとっては役立つかもしれませんが、次のライブラリルーチンにTDDを使用することをお勧めします。実行可能な仕様をゆっくり設定し、コードがテストに合格するようにします。完了すると、ライブラリの呼び出し方法を確認する必要があるすべての人が実行可能な仕様を利用できるようになります。
「ケーススタディの結果は、4つの製品のリリース前の欠陥密度が、TDDプラクティスを使用しない同様のプロジェクトと比較して40%から90%減少したことを示しています。主観的に、チームは15〜35%の増加を経験しました。 TDD採用後の最初の開発期間」 〜 4つの産業チームの結果と経験
ソフトウェアを作成するプロセスは、コードを記述するプロセスではありません。最初に「広範囲」の計画なしにソフトウェアプロジェクトを開始することはできません。川の2つの岸をつなぐプロジェクトのように、最初にそのような計画が必要です。
TDDのアプローチは、(ほとんど)ユニットテストに関連しています。少なくともそれは、人々がそれについて考える傾向があることです。つまり、ソフトウェアコードの最も低レベルのビットを作成しています。すべての機能と動作がすでに定義されていて、達成したいことが実際にわかっている場合。
構造工学では、次のようになります。
「これらの2つの金属片が接続されており、この接続では、xのオーダーのせん断力を維持する必要があります。これを行うのに最適な接続方法をテストしてみましょう '
ソフトウェアが全体として機能するかどうかをテストするために、ユーザビリティテスト、統合テスト、受け入れテストなど、他の種類のテストを設計します。これらも、コードの記述に関する実際の作業が始まる前に定義する必要があり、単体テストが成功した後に実行されます。
Vモデルを参照してください: http://en.wikipedia.org/wiki/V-Model_%28software_development%29
ブリッジでどのように機能するか見てみましょう。
地方自治体は、橋梁建設会社に次のように述べています。「これら2つのポイントを接続するための橋が必要です。橋は、1時間あたりn個のトラフィックを許可し、2012年12月21日に準備ができている必要があります」-これは、受け入れテスト:テストに合格しなかった場合、会社は全額(または一部)のお金を受け取りません。
会社の経営陣がプロジェクトのスケジュールを決定します。彼らは作業チームを設定し、各チームの目標を設定しました。チームがこれらの目標を達成しない場合、橋は予定通りに建設されません。ただし、ここにはある程度の柔軟性があります。チームのいずれかに問題がある場合、会社は要件を変更し、下請業者を変更し、より多くの人員を雇うなどしてプロジェクト全体がポイント#1で設定された目標を依然として満たすようにそれを相殺できます。
特定のブリッジコンポーネントの設計を担当するチーム内では、上記の例のように見えます。ブリッジの構築に関する知識が豊富であるため、解決策が明白な場合があります(ソフトウェア開発で十分にテストされたライブラリを使用するようなものです-宣伝どおりに機能すると想定しているだけです)。時には、いくつかのデザインを作成してテストし、最適なものを選択する必要があります。それでも、コンポーネントがテストされる基準は事前にわかっています。
私の心の中でTDDは機能します
特にあなたが提起するポイント
TL; DR
プログラミングはまだ設計作業であり、構築ではありません。事実の後にユニットテストを書くことは、コードがそれがすることをすることを確認するだけであり、それが何か有用なことをするのではありません。テストの失敗は間違いを早期に発見できるため、真の価値です。
コードは設計です
[〜#〜] ppp [〜#〜] の第7章では、「ボブおじさん」がこの問題について直接語っています。この章の非常に早い段階で、彼は 優れた記事 を参照しており、コードはデザインであると提案しています(リンクは、トピックに関する彼の3つの記事すべてを集めたページにリンクしています)。
この議論について興味深いのは、構築が非常に高価なアクティビティである他の工学分野とは異なり、ソフトウェアの構築は比較的無料であるということです(IDEでコンパイルすると、ソフトウェア。コードの作成を構築アクティビティではなく設計アクティビティと見なす場合、赤、緑、リファクタリングのサイクルは基本的に設計の練習です。テストを記述し、それらを満たすコードをリファクタリングして、新しいコードを既存のシステムに統合します。
仕様としてのTDD
TDD用に作成する単体テストは、仕様を理解した上で、仕様を直接翻訳したものです。仕様を最小限に満たす(テストをグリーンにする)コードを記述することにより、記述したすべてのコードが特定の目的のために存在します。その目的が達成されたかどうかは、繰り返し可能なテストによって検証されます。
機能へのテストの書き込み
ユニットテストでよくある間違いは、コードの後にテストを記述したときに発生し、コードが実行することをテストすることになります。つまり、このようなテストが表示されます
public class PersonTest:Test
{
[Test]
TestNameProperty()
{
var person=new Person();
person.Name="John Doe";
Assert.AreEqual("John Doe", person.Name);
}
}
私はこのコードが役に立つと思いますが(誰かが単純なプロパティでわいせつなことをしていないことを確認してください)。仕様の検証には役立ちません。そして、あなたが言ったように、これらの種類のテストを書くことはあなたを今のところ取りません。
グリーンは良いのですが、価値はレッドにあります予期しないテストエラーが発生したとき、TDDで最初の真の「あは」の瞬間がありました。私は自分が構築しているフレームワークに対して持っていた一連のテストを行いました。新しい機能を追加して、そのテストを作成しました。次に、テストに合格するためのコードを記述しました。コンパイル、テスト...新しいテストでグリーンを獲得しました。しかし、私が赤になるとは思っていなかった別のテストでも赤になりました。
失敗を見て、私はそのテストを実施していなかったらかなり長い間そのバグを捕まえていたとは思えないので、安堵のため息をつきました。そして、それは非常に厄介なバグでした。幸いなことに、私はテストを受け、バグを修正するために何をする必要があるかを正確に教えてくれました。テストがなければ、私はシステムを構築し続け(バグがそのコードに依存する他のモジュールに感染する)、バグが発見されるまでには、それを適切に修正することが主要な作業でした。
TDDの真の利点は、無謀な放棄で変更を加えることができることです。プログラミングのセーフティネットのようなものです。空中ブランコのアーティストがミスをして倒れたらどうなるか考えてみてください。ネットでは、それは恥ずかしい間違いです。なしで、それは悲劇です。同様に、TDDは骨の折れるミスをプロジェクトを殺す災害に変えることからあなたを救います。
テストがアプリケーションを証明することは、テスト駆動開発、またはテスト駆動Design(それらは異なる)を擁護する人を見つけることはできません。だから、それをストローマンと呼んで完了させましょう。
テストは時間と労力の浪費だと言っているTDDを嫌いまたは感動しない人は見つかりません。テストはアプリケーションを証明しませんが、エラーを見つけるのに非常に役立ちます。
これらの2つのことを述べれば、どちらの側も実際にソフトウェアのテストを実行することに関して何も変わっていません。どちらもテストを行っています。どちらも、できるだけ多くのバグを見つけるためにテストに依存しています。また、どちらもテストを使用して、ソフトウェアプログラムが機能していること、およびその時点で発見できることを確認しています。半分の手掛かりを持つ人はテストなしでソフトウェアを販売していませんし、半分の手掛かりを持つ誰もテストが彼らが販売するコードを完全にバグのないものにすることを期待することを期待していません。
TDDとnot-TDDの違いは、テストが行われていることではありません。違いは、テストがいつ記述されるかです。 TDDでは、テストはソフトウェアの前に記述されます。非TDDでは、テストはソフトウェアの後に、またはソフトウェアと連携して作成されます。
後者に関して私が見た問題は、テストは、目的の結果や仕様よりも多く書かれているソフトウェアを対象とする傾向があるということです。テストチームが開発チームから分離している場合でも、テストチームはソフトウェアを見て、それを操作し、それを対象とするテストを作成する傾向があります。
プロジェクトの成功を研究する人たちが何度も気づいたことの1つは、顧客が必要なものをレイアウトする頻度、開発担当者が実行して何かを書くこと、そして顧客が「完了」と言って戻ってきたときです。それは、顧客が要求したものとは完全に完全に異なるものであることが判明しました。 「しかし、すべてのテストに合格しています...」
TDDの目標は、この「循環論法」を打ち破り、ソフトウェアではないソフトウェアをテストするテストの基礎を提供することです。テストは、「顧客」が望む行動をターゲットにするように書かれています。次に、これらのテストに合格するようにソフトウェアが作成されます。
TDDはpartですが、この問題に対処するためのソリューションです。それはあなたがする唯一のステップではありません。あなたがする必要がある他のことは、より多くの顧客フィードバックがより頻繁にあることを確認することです。
私の経験では、TDDを正常に実装することは非常に困難です。多くの自動テストでは、自動化ソフトウェアを正しく機能させるために何かを試してみる必要があるため、製品が登場する前にテストを作成することは困難です。単体テストに慣れていない開発者がそれを行うことも困難です。何度も何度も、チームの人々に最初にテストを書くように言いました。私は実際にそれをするために1つも得たことがありません。結局、時間の制約と政治によってすべての努力が打ち消されたため、ユニットテストすらまったくできなくなりました。もちろん、これは必然的に、設計が偶然かつ厳密に結合されることにつながります。そのため、たとえ私たちが望んだとしても、実装するのに法外な費用がかかることになります。これを回避することがTDDが開発者に最終的に提供するものです。
TDDはnot設計をスキップする言い訳です。彼らがすぐにコーディングを始めることができたとしても、「アジャイル」バンドワゴンで多くのジャンプを見てきました。真のアジャイルを使用すると、ウォーターフォールプロセスに影響を与えた(他の分野の)エンジニアリングの優れたプラクティスよりもはるかに速くコーディングを開始できます。
テストが設計を推進していると言うとき、それは単に、テストが完了する前の非常に早い段階でテストを使用できることを意味します。このテストを行うことは、製品が完成するずっと前に、灰色の領域に挑戦し、現実の世界と対戦することにより、設計に強く影響します。これを考慮に入れるために、設計に戻って調整することを頻繁に強制します。
私の意見では、TDDは単にテストをintegralの設計の一部にして、それを検証するために最後に行うものではありません。 TDDの使用を開始するにつれ、システムを設計するときにシステムを破壊または破壊する方法についての考え方が身に付きます。個人的には、常に最初にテストを行うわけではありません。確かに私はインターフェイスで明白な(ユニット)テストを行いますが、実際の利益は、このデザインが壊れる可能性のある新しい創造的な方法を考えるときに作成する統合テストと仕様テストから得られます。方法を考えたらすぐに、そのためのテストをコーディングし、何が起こるかを確認します。時々私は結果に耐えることができます、この場合、メインビルドの一部ではない別のプロジェクトにテストを移動します(失敗し続けるため)。
TDDでは、ここで駆動されるとは、テストが設計に強く影響し、実際に駆動していると感じることができることを意味します。しかし、それはそれで止まり、ここで私はあなたの懸念を理解します、それは少し怖いです...誰がショーを運転しますか?
[〜#〜]あなた[〜#〜]テストではなく運転しています。テストはそこにあるので、あなたが進むにつれて、あなたが作成したものに良いレベルの信頼を得ることができるので、それがしっかりした根拠に基づいていることをさらに知ることができます。
正確に、したがってTDDで駆動されます。テストが全体を推進しているのはそれほどではありませんが、それらは、物事の方法、システムの設計方法および考え方に非常に大きな影響を与え、思考プロセスの大部分をテストに委任し、その見返りに返します。彼らはあなたのデザインに深い影響を与えます。
すぐに停止してください...ソフトウェアエンジニアリングは、他のエンジニアリングプラクティスとはまったく異なります。実際、ソフトウェアエンジニアリングは、実際には、文献と多くの共通点があります。完成した本を取り、それから4つのチャプターをリッピングし、2つの新しいチャプターを書き替えて、それらを本に戻し、それでも良い本を手に入れることができます。優れたテストとソフトウェアを使用すると、システムの任意の部分をリッピングして別の部分に置き換えることができます。そうすることのコストは、最初にそれを作成した場合よりもはるかに高くはありません。実際、テストを実施してデザインに十分な影響を与えることができれば、最初から作成するよりもはるかに安くなる可能性があります。これは、この置き換えによってテストがカバーするものを壊さないという一定の自信があるためです。
テストにはビルドとはまったく異なる考え方が必要だからです。すべての人が元の状態に戻ったり、元の状態に戻ったりできるわけではありません。実際、作成を破棄するように心がけられないために、適切なテストを作成できない人もいます。これにより、テストが少なすぎるプロジェクト、またはターゲットメトリックに到達するのに十分なだけのテストが生成されます(コードカバレッジが頭に浮かびます)。彼らはパステストと例外テストを喜ぶでしょうが、コーナーケースと境界条件を忘れます。
他の人たちは、部分的または完全に設計を放棄するテストに依存します。それを行う各メンバーは、お互いに統合することです。デザインは何よりもまずコミュニケーションツールであり、これが私がいる場所だと言うために地面に設定されたステーク、これがドアと窓がある場所だと言うスケッチです。これがないと、あなたが何をテストしたかに関係なく、あなたのソフトウェアは運命づけられます。統合とマージは常に苦痛であり、抽象化の最高レベルでのテストに欠けます。
これらのチームをTDDするのは、道のりではないかもしれません。
TDDを使用すると、テストが簡単または迅速でないコードを記述しない傾向があります。これは小さなことのように思えるかもしれませんが、リファクタリング、テスト、テストによるバグの再現、および修正の検証がいかに簡単であるかに影響を与えるため、プロジェクトに大きな影響を与える可能性があります。
また、テストでサポートされているコードの因数分解を改善すると、プロジェクトの新しい開発者がすぐに理解できるようになります。
自分でTDDをあまり練習していませんが、これについてはよく考えています。コード品質と次のTDDの間には(強い?)正の相関があるようです。
1)私の最初の見解は、これは(主に)TDDが(それ自体)コードに「より良い品質」を追加することに起因するものではなく、TDDが最悪の部分と習慣を取り除き、間接的に品質を高めるのに役立つようなものです。
私はそれ自体がテストではないことを主張します-それはwriteそれらのテストのプロセスです。悪いコードのテストを書くのは難しいですし、逆もまた同じです。そして、プログラミング中にこれを頭の後ろに保つことで、多くの悪いコードを排除します。
2)別の観点(これは哲学的になりつつある)は、主人の精神的習慣に従うことです。あなたは彼の「外部の習慣」(長いひげが良いなど)に従ってマスターになることを学ぶのではなく、彼の内部の考え方を学ぶ必要があり、これは難しいです。そして、どういうわけか、(初心者)プログラマーにTDDをフォローさせ、彼らの考え方をマスターの考え方に近づけます。
「書き込みテスト+パスまでリファクタリング」というアプローチは、信じられないほどアンチエンジニアリングに見えます。
リファクタリングとTDDの両方について誤解しているようです。
コードリファクタリング は、ソフトウェアの一部の非機能属性を改善するために、外部機能の動作を変更せずにコンピュータープログラムのソースコードを変更するプロセスです。
したがって、通過するまでコードをrefactorすることはできません。
また、TDD、特に単体テスト(他のテストは私にはかなり妥当と思われるため、コアの改善を検討しています)は、機能するまでコンポーネントを再設計することではありません。これは、コンポーネントが設計どおりに機能するまで、コンポーネントを設計して実装に取り組むことです。
また、unitテストはunitsをテストすることであることをよく理解することが重要です。常に多くのものを最初から作成する傾向があるため、そのようなユニットをテストすることが重要です。土木技師は、使用するユニット(さまざまな材料)の仕様をすでに知っており、それらが機能することを期待できます。これらはソフトウェアエンジニアには当てはまらない場合が多く、テスト済みの高品質のコンポーネントを使用することを意味するため、ユニットを使用する前にテストすることは非常にプロエンジニアリングです。
土木技師がスタジアムを覆う屋根を作るために新しい繊維組織を使用するアイデアを持っている場合、彼はそれをユニットとしてテストすること、つまり必要な仕様(たとえば、重量、透過性、安定性)を定義することを期待します。など)、その後、それらが満たされるまでテストおよび調整します。
それがTDDが機能する理由です。テストされたユニットのソフトウェアを構築する場合、それらを一緒にプラグインすると、それが機能する可能性がはるかに高くなるので、テストが十分なカバレッジを前提として、グルーコードに問題があると期待できます。
edit:
リファクタリングとは:no機能の変更。単体テストを作成する際の1つのポイントは、リファクタリングによってコードが破損しないことを確認することです。したがって、TDDは、リファクタリングに副作用がないことを保証するためのものです。
粒度は正確には定義されていないため、前述のとおり、ユニットテストではユニットではなくテストユニットをテストするため、粒度は視点の対象ではありません。
TDDは優れたアーキテクチャを推奨します。すべてのユニットの仕様を定義して実装する必要があり、実装の前にそれらを設計する必要があります。これは、あなたが考えているように思われることとはまったく逆です。 TDDはユニットの作成を指示します。これは個別にテストできるため、完全に分離されます。
TDDは、スパゲッティコードでソフトウェアテストを実行し、パスタがパスするまでパスタをかき混ぜるという意味ではありません。
土木工学とは対照的に、ソフトウェア工学では、プロジェクトは通常常に進化します。土木工学では、位置Aに橋を建設する必要があります。橋は、xトンを運ぶことができ、1時間あたりn台の車両に十分な幅があります。
ソフトウェアエンジニアリングでは、顧客は基本的に任意の時点(おそらく完了後)で、ダブルデッキブリッジを望んでおり、最寄りの高速道路に接続することを望んでおり、リフティングにしたいと考えています。彼の会社が最近帆船を使い始めたので、橋。
ソフトウェアエンジニアは、設計の変更を任されています。彼らのデザインに欠陥があるからではなく、それが手口だ。ソフトウェアが適切に設計されている場合は、低レベルのコンポーネントをすべて書き換える必要なく、高レベルで再設計できます。
TDDは、個別にテストされ、高度に分離されたコンポーネントを使用してソフトウェアを構築することです。適切に実行されれば、要件の変更に対応することが、必要な場合よりも大幅に迅速かつ安全になります。
TDDは開発プロセスに要件を追加しますが、品質保証の他の方法を禁止しません。確かに、TDDは正式な検証と同じセキュリティを提供していませんが、正式な検証は非常にコストがかかり、システムレベルでは使用できません。それでも、必要に応じて、両方を組み合わせることができます。
TDDには、システムレベルで実行される単体テスト以外のテストも含まれます。これらは説明するのは簡単ですが、実行するのが難しく、測定するのが難しいと思います。また、それらはかなりもっともらしいです。絶対に必要だとは思いますが、アイデアとしては評価していません。
結局のところ、実際に問題を解決するツールはありません。ツールは問題の解決を容易にするだけです。あなたは尋ねることができます:ノミは素晴らしい建築でどのように私を助けますか?まっすぐな壁を作るつもりなら、まっすぐなレンガが役に立ちます。確かに、もしあなたがそのツールを馬鹿に与えると、おそらく彼は最終的に彼の足でそれを叩きますが、初心者に誤った安全性を与えるのはTDDの欠陥ではないので、それはノミのせいではありません。良いテストを書いていない人。
つまり、最終的には、TDDがTDDがない場合よりもはるかにうまく機能すると言えます。
あなたは間違った角度から最初のポイントに近づいていると思います。
理論的な観点から見ると、障害点をチェックすることで何かが機能することを証明しています。それが使用される方法です。何かが機能していることを証明する方法は他にもたくさんあるかもしれませんが、TDDはビット単位のアプローチの単純さのために確立されています。
実際には、これは暗黙のうちに次のように変換されます。次のことに進むことができます(すべての述部を満たすためにTDDを正常に適用した後)。この観点からTDDにアプローチする場合、それは「テストの書き込み+パスまでのリファクタリング」ではなく、これを完了したことに関するものであり、今、次の機能に最も焦点を当てています重要なこと。
これが土木工学にどのように適用されるか考えてください。 15万人の観客を収容できるスタジアムを構築しています。スタジアムの構造的完全性が健全であることを証明した後、私たちはsafety firstを満足しました。洗面所、屋台、座席など、すぐに重要になる他の問題に焦点を当てることができるようになりました...観客の体験をより楽しいものにします。 TDDにはさらに多くの機能があるため、これは単純化しすぎですが、肝心なのは、新機能とエキサイティングな機能の両方に重点を置き、同時に整合性を維持する場合に、最高のユーザーエクスペリエンスを実現できないということです。どちらの場合も途中で取得します。つまり、どのようにして正確に知ることができますかhow多くの洗面所と150000人のためにどこに置くべきですか?自分の生涯でスタジアムが倒壊することはめったにありませんが、ハーフタイムの間、多くの場合、列に並んで待たなければなりませんでした。つまり、トイレの問題は間違いなく複雑であり、エンジニアが安全に費やす時間を短縮できれば、最終的にトイレの問題を解決できる可能性があります。
あなたの2番目のポイントは無関係です。なぜなら、絶対は fools endeavor であることにすでに同意しており、ハンクムーディはそれらが存在しないと言っているからです(しかし、その参照を見つけることができないようです)。
「ユーザーではなくテストが要件を設定する」というあなたの言い方は好きではありません。 TDDでの単体テストのみを検討していると思いますが、統合テストについても取り上げています。
ソフトウェアのベースを構成するライブラリのテストとは別に、ユーザーがソフトウェア/ウェブサイト/その他とどのようにやり取りするかをカバーするテストを記述します。これらはユーザーから直接提供され、cucumber(http://cukes.info)などのライブラリを使用すると、ユーザーが自然言語でテストを作成することもできます。
TDDはコードの柔軟性も促進します。何かのアーキテクチャの設計に永遠に費やした場合、後で必要に応じてそれらの変更を行うのは非常に困難になります。いくつかのテストを書くことから始めて、それらのテストに合格する小さなコードを書きます。テストを追加し、コードを追加します。コードを根本的に変更する必要がある場合でも、テストは成功します。
橋や車とは異なり、1つのソフトウェアはその寿命の間に大きな変更を受ける可能性があり、最初にテストを記述せずに複雑なリファクタリングを実行するのは、単に尋ねるの問題です。
バグの発見が早ければ早いほど、それらを修正するコストが少なくて済み、それだけでTDDに価値があります。
ソフトウェアエンジニアリングにおけるTDDは、アプリケーションでのエラー処理と同様に、ロギングと診断(エラー処理の一部ですが)と同様に、適切な方法です。
TDDは、ソフトウェア開発を試行錯誤によるコーディングに減らすためのツールとしては使用できません。それでも、ほとんどのプログラマーは、ランタイムログを見つめたり、デバッガーで例外を監視したり、アプリのコーディング/コンパイル/実行で構成される開発フェーズ中に、失敗/成功の他の兆候を一日中使用します。
TDDは、開発者としての生産性を高めるためにこれらのステップを形式化および自動化するための方法にすぎません。
1)ソフトウェアエンジニアリングと橋梁建設を比較することはできません。橋梁建設の柔軟性は、ソフトウェアプログラムの設計の柔軟性にほど遠いものです。ブリッジを構築することは、同じプログラムを損失の多いマシンに何度も何度も書くようなものです。ソフトウェアのようにブリッジを複製して再利用することはできません。各ブリッジは一意であり、製造する必要があります。同じことが車や他のデザインにも当てはまります。
ソフトウェアエンジニアリングで最も難しいのは、障害を再現することです。通常、ブリッジに障害が発生した場合、問題の原因を特定することは非常に簡単で、理論的には障害を再現することは簡単です。コンピュータプログラムが失敗すると、複雑な一連のイベントによってシステムが障害のある状態になり、エラーの場所を特定することが非常に難しくなります。 TDDと単体テストにより、ソフトウェアコンポーネント、ライブラリ、アルゴリズムの堅牢性を簡単にテストできます。
2)弱い単体テストと浅いテストケースを使用してシステムにストレスを与えず、誤った自信を構築することは、単に悪い習慣です。システムのアーキテクチャーの品質を無視して、テストを実行するだけでも、もちろん悪いことです。しかし、超高層ビルや橋の建設場所で素材を節約し、設計図に従わないのは不正行為であり、それは常に起こります...
簡単な回答をさせていただきます。通常、TDDは単体テストと同じように間違った方法で見られます。ユニットテスティングについては、良いテクニカルトークのビデオを見てから最近まで理解できませんでした。基本的にTDDは、次のことを機能させたいと言っているだけです。それらは実装されなければなりません。次に、残りのソフトウェアを通常どおりに設計します。
ライブラリを設計する前に、ライブラリのユースケースを書くようなものです。ただし、ライブラリのユースケースは変更でき、TDDは変更できない場合があります(私はAPI設計にTDDを使用しています)。また、テストを追加して、テストが取得する可能性のある野生の入力/使用について考えることをお勧めします。ライブラリまたはAPIを作成するときに便利です。何かを変更した場合、何かを壊したことを知っておく必要があります。ほとんどの日常のソフトウェアでは、ユーザーがボタンを押すためのテストケースが必要な理由や、CSVリストまたは1行に1つのエントリがあるリストを受け入れる必要があるので、私は気にしません。これを変更するには、TDDを使用しないでください。
TDDが機能する理由
そうではありません。
明確化:自動テストは、テストなしよりも優れています。しかし私は個人的にユニットテストのほとんどは無駄であり、それらは通常トートロジーであり(つまり、テスト中の実際のコードから明らかなことを言います)、一貫して冗長ではなく、すべての境界ケースをカバーすることを簡単に証明することはできません(エラーが通常発生する場所) )。
そして最も重要なことは、優れたソフトウェア設計は、多くのアジャイル/ TDDエバンジェリストによって宣伝されているため、魔法のようにテストから外れることはありません。そうでないと主張する人は、これを証明する査読済み科学研究へのリンク、または少なくともコード変更履歴によってTDDの利点を研究できるいくつかのオープンソースプロジェクトへの参照を提供してください。
TDDは実際にはテストに関するものではありません。そして、それは確かに良いテストの代わりにはなりません。それがあなたに与えるものはdesignであり、それは十分に考え抜かれており、消費者が簡単に消費でき、後でメンテナンスやリファクタリングが簡単です。その結果、バグが減り、より適応性の高いソフトウェア設計が実現します。また、TDDは、想定を熟考し、文書化するのにも役立ちます。想定の一部が正しくないことがよくあります。プロセスの非常に早い段階でこれらを見つけます。
そして、Niceの副次的な利点として、リファクタリングがソフトウェアの動作(入力と出力)を変更しないことを確認するために実行できるテストの大きなスイートがあります。
構造工学が具体的である場合、ソフトウェアは有機的です。
あなたがあなたの橋を建てるとき、それは橋のままであり、それが短期間に何か他のものに発展することはほとんどありません。改善は数か月と数年にわたって行われますが、ソフトウェアのように数時間と数日では行われません。
単独でテストする場合、通常は2種類のフレームワークを使用できます。制約付きフレームワークと制約なし。制約のないフレームワーク(.NET)を使用すると、アクセス修飾子に関係なく、すべてをテストして置き換えることができます。つまりプライベートおよび保護されたコンポーネントをスタブおよびモックできます。
私が見たほとんどのプロジェクトは制約されたフレームワーク(RhinoMocks、NSubstitute、Moq)を使用しています。これらのフレームワークを使用してテストする場合、実行時に依存関係を注入および置換できるようにアプリケーションを設計する必要があります。これは、疎結合設計が必要であることを意味します。緩やかに結合された設計(正しく実行された場合)は、懸念の分離が向上することを意味します。これは良いことです。
要約すると、この背後にある考え方は、デザインがテスト可能である場合、疎結合であり、懸念事項を適切に分離していると考えています。
余談ですが、私は実際にはテスト可能でしたが、オブジェクト指向の設計の観点からは不十分に記述されたアプリケーションを見てきました。