テスト駆動設計を採用すると何が失われますか?
ネガのみをリストします。否定的な形で書かれた利点を挙げないでください。
テスト駆動設計を採用すると何が失われますか?
ネガのみをリストします。否定的な形で書かれた利点を挙げないでください。
回答:
いくつかの不利な点があります(そして、特にプロジェクトの基礎を書くときに、利点がないと主張していません-それは最後に多くの時間を節約します):
「実際の」TDD(読み取り:最初に赤、緑、リファクターステップでテストする)を実行する場合は、統合ポイントをテストするときにモック/スタブの使用を開始する必要もあります。
モックの使用を開始するとき、しばらくすると、依存性注入(DI)と制御の反転(IoC)コンテナーの使用を開始する必要があります。そのためには、すべてにインターフェースを使用する必要があります(それ自体に多くの落とし穴があります)。
結局のところ、単に「古い方法」で行う場合よりも、はるかに多くのコードを記述する必要があります。単なる顧客クラスの代わりに、インターフェース、モッククラス、いくつかのIoC構成、およびいくつかのテストを作成する必要もあります。
また、テストコードも維持および管理する必要があります。テストは他のすべてと同じように読みやすくする必要があり、優れたコードを書くには時間がかかります。
多くの開発者は、これらすべてを「正しい方法」で行う方法を完全に理解していません。しかし、TDDがソフトウェアを開発するための唯一の真の方法であると誰もが言うので、彼らはできる限り最善を尽くします。
想像以上に難しいです。多くの場合、TDDを使用して行われたプロジェクトは、誰も本当に理解していない大量のコードを生成します。単体テストは、多くの場合、間違ったもの、間違った方法をテストします。そして、いわゆるテストの達人でさえも、良いテストがどのように見えるべきかについて誰も同意しません。
これらすべてのテストにより、システムの動作を「変更」する(リファクタリングとは逆に)のが非常に難しくなり、単純な変更が非常に難しくなり、時間がかかります。
TDDの資料を読むと、常に非常に優れた例がいくつかありますが、実際のアプリケーションでは、多くの場合、ユーザーインターフェイスとデータベースが必要です。これはTDDが本当に難しくなる場所であり、ほとんどのソースは良い答えを提供していません。そして、もしそうなら、それは常により多くの抽象化を含みます:モックオブジェクト、インターフェースへのプログラミング、MVC / MVPパターンなど、これもまた多くの知識を必要とします...そしてさらに多くのコードを書かなければなりません。
ですので、注意してください...熱心なチームがなく、優れたテストを書く方法を知っていて、優れたアーキテクチャに関するいくつかのことを知っている経験豊富な開発者が1人もいない場合、TDDの道を進む前によく考えなければなりません。 。
多数のテストがあるポイントに達した場合、システムを変更すると、変更によって無効にされたテストに応じて、テストの一部またはすべてを書き直すことが必要になる場合があります。これは、比較的迅速な変更を非常に時間のかかるものに変える可能性があります。
また、実際に優れた設計担当者よりもTDDに基づいて設計決定を始める場合もあります。TDDが要求する方法をテストすることは不可能である非常にシンプルで簡単なソリューションがあったかもしれませんが、実際には間違いを起こしやすいはるかに複雑なシステムがあります。
if part of the system is covered by tests and they pass, then everything is fine (including design)
。
私にとって最大の問題は、「それに取り掛かる」のに要する時間が大幅に失われることです。私はまだTDDの旅の始まりに非常に近く(興味があれば、私のテストアドベンチャーの更新については私のブログを参照してください)、文字通り何時間もかけて始めました。
脳を「テストモード」にするのに長い時間がかかり、「テスト可能なコード」を書くこと自体がスキルです。
TBH、私はプライベートメソッドを公開することについてのJason Cohenのコメントに敬意を払いません。それはそれについてではありません。私はこれまでよりも新しい働き方でパブリックメソッドを作成していません。ただし、アーキテクチャの変更が必要であり、コードの「ホットプラグ」モジュールを使用して、他のすべてのものをテストしやすくすることができます。これを行うには、コードの内部にアクセスしやすくするべきではありません。それ以外の場合は、すべてがパブリックであるスクエア1に戻ります。そのカプセル化はどこにありますか?
つまり、(IMO)一言で言えば:
PS:ポジティブへのリンクが必要な場合は、いくつかの質問をして回答しました。私のプロフィールを確認してください。
私がテスト駆動開発を実践してきた数年の間に、最大の欠点は次のとおりです。
TDDはペアで行うのが最適です。あなたはとき一つには、それだけで実装を作成する衝動に抵抗するのは難しい知って書き込む方法の場合/他の文を。しかし、あなたが彼を任務に留めているので、ペアはあなたを任務に留めます。残念なことに、多くの企業/マネージャーは、これがリソースの有効利用であるとは考えていません。同時に2つの機能を実行する必要があるのに、1つの機能を作成するのに2人で支払うのはなぜですか?
一部の人々はユニットテストを書くための忍耐力がありません。彼らの仕事をとても誇りに思う人もいます。または、複雑なメソッド/関数が画面の端から流れ出るのを見るようなものもあります。TDDはすべての人に適しているわけではありませんが、本当にそうであるといいのですが。コードを継承する貧しい人々にとって、それはものを維持することをとても簡単にします。
理想的には、テストは、コードを間違って決定した場合にのみ中断します。つまり、システムは一方向に機能すると思っていましたが、機能しないことがわかりました。テストまたは(小さな)テストのセットを壊すことによって、これは実際に良いニュースです。新しいコードがシステムにどのように影響するかを正確に知っています。ただし、テストの記述が不十分、密結合、またはさらに悪い場合は生成された場合(咳 VSテスト)、テストの維持がすぐに合唱になる可能性があります。そして、十分なテストが開始して、それらが作成していると認識された値よりも多くの作業を引き起こすようになった後、スケジュールが圧縮されたときに、テストが最初に削除されます(たとえば、処理時間に達した場合)。
理想的には、ここでも、方法論を順守する場合、コードはデフォルトで100%テストされます。通常、私はコードカバレッジが90%以上になると思っていました。これは通常、いくつかのテンプレートスタイルのアーキテクチャがあり、ベースがテストされているときに、テンプレートのカスタマイズをテストせずに隅を切り取ろうとしたときに発生します。また、私が以前に経験したことのない新しい障壁に遭遇したとき、それをテストする際に学習曲線があることがわかりました。私はいくつかのコード行を古いskoolの方法で書くことを認めますが、私はそれを100%にするのが本当に好きです。(私は学校で過大な達成者だったと思います、er skool)。
ただし、TDDの利点は、アプリケーションをカバーする一連の優れたテストを達成できても、1つの変更ですべてが壊れるほど脆弱ではないという単純な考えの欠点をはるかに上回っていると私は言います。プロジェクトの1日目と同じように、プロジェクトの300日目に新しい機能を追加し続けることができます。これは、TDDを試すすべての人が、バグに覆われたすべてのコードの魔法の弾丸であると考えているわけではありません。機能しない、期間。
個人的には、TDDを使用すると、より単純なコードを記述し、特定のコードソリューションが機能するかどうかの議論に費やす時間が減り、以下に示す基準を満たさないコード行を変更する恐れがないことがわかりましたチーム。
TDDは習得するのが難しい分野です。私は数年このTDDに取り組んでいますが、それでも新しいテスト手法を常に学んでいます。事前に莫大な時間を投資することですが、長期的には、自動化された単体テストがない場合よりも持続可能性がはるかに高くなります。さて、私のボスだけがこれを理解できたら。
最初のTDDプロジェクトでは、時間と個人の自由という2つの大きな損失があります。
あなたは時間を失う:
次の理由で個人の自由を失う:
お役に立てれば
TDDでは、これらのテストに合格するコードを記述する前に、クラスがどのように動作するかを計画する必要があります。これはプラスにもマイナスにもなります。
「真空」でコードを書く前にテストを書くのは難しいと思います。私の経験では、最初のテストの作成中に忘れていたクラスを作成しているときに必然的に何かを考えるときはいつでも、自分のテストをトリップする傾向があります。次に、クラスをリファクタリングするだけでなく、テストも行います。これを3〜4回繰り返すと、イライラすることがあります。
最初にクラスのドラフトを作成してから、一連の単体テストを作成(および保守)することを好みます。下書きを作成した後、TDDは問題なく機能します。たとえば、バグが報告された場合、そのバグを悪用するためのテストを記述し、テストに合格するようにコードを修正します。
さて、このストレッチでは、テストをデバッグする必要があります。また、テストの作成にはある程度のコストがかかりますが、ほとんどの人は、デバッグ時間の節約と安定性の両方の点で、アプリケーションの存続期間を通じて成果を上げる先行投資であることに同意します。
しかし、私が個人的に抱えていた最大の問題は、実際にテストを作成するための規律を立てることです。チーム、特に確立されたチームでは、費やした時間に価値があると彼らを納得させるのは難しい場合があります。
TDDの欠点は、通常、「アジャイル」の方法論と密接に関連しているため、システムの文書化は重要ではなく、テストが特定の値を返す必要がある理由が、開発者にのみ存在するのではなく、その背後にあるという理解です。頭。
テストが特定の値ではなく他の特定の値を返す理由を開発者が去るまたは忘れるとすぐに、あなたはうんざりしています。TDDは、適切に文書化され、人間が読める(つまり、先のとがった髪のマネージャー)文書で囲まれていれば問題ありません。5年間で世界が変わり、アプリも同様に参照できるようになります。
ドキュメンテーションについて話すとき、これはコードの言い訳ではありません。これは、アプリケーションの外部に存在する公式な記述です。たとえば、マネージャー、弁護士、および更新しなければならない貧しいsapが参照できるユースケースや背景情報などです。 2011年のコード。
TDDに夢中になるいくつかの状況に遭遇しました。名前を付けるには:
テストケースの保守性:
大企業の場合、多くの場合、自分でテストケースを作成する必要がないか、少なくともほとんどの場合、会社に入社したときに他の人がテストケースを作成します。アプリケーションの機能は随時変更され、HP Quality Centerなどのシステムを配置してそれらを追跡する機能がないと、すぐに夢中になります。
これはまた、テストケースで何が行われているのかを把握するには、新しいチームメンバーにかなりの時間がかかることを意味します。次に、これはより多くの必要なお金に変換できます。
テスト自動化の複雑さ:
テストケースの一部またはすべてを自動化してマシンで実行可能なテストスクリプトにする場合は、これらのテストスクリプトが対応する手動テストケースと同期し、アプリケーションの変更に沿っていることを確認する必要があります。
また、バグの発見に役立つコードのデバッグにも時間を費やします。私の意見では、これらのバグのほとんどは、テストチームがアプリケーションの変更を自動化テストスクリプトに反映できなかったことが原因です。ビジネスロジック、GUI、およびその他の内部的な要素の変更により、スクリプトの実行が停止したり、実行が不安定になったりする可能性があります。変更は非常に微妙で、検出が難しい場合があります。テーブル1がテーブル2になったときに、テーブル1からの情報に基づいて計算を行ったため、すべてのスクリプトが失敗を報告します(誰かがアプリケーションコードでテーブルオブジェクトの名前を入れ替えたため)。
最大の問題は、適切な単体テストの書き方を知らない人々です。それらは互いに依存するテストを記述します(そして、Antで実行するとうまく機能しますが、Eclipseから実行すると、それらが異なる順序で実行されるという理由だけですべてが突然失敗します)。彼らは特に何もテストしないテストを書きます-彼らは単にコードをデバッグし、結果をチェックし、それをテストに変更して、それを「test1」と呼びます。それらがユニットテストを書くのが簡単になるからといって、それらはクラスとメソッドのスコープを広げます。単体テストのコードはひどいもので、すべての古典的なプログラミングの問題(重い結合、500行の長さのメソッド、ハードコードされた値、コードの重複)があり、維持するのは大変です。奇妙な理由で、人々はユニットテストを「実際の」コードよりも劣ったものとして扱います。tすべての品質を気にします。:-(
テストの作成に費やされた多くの時間を失います。もちろん、これはプロジェクトの終わりまでにバグをより早く見つけることで保存されるかもしれません。
すべてのコードをテストする前に、「完了」したとは言えなくなります。
実行する前に、数百または数千行のコードを書き込む機能を失います。
デバッグを通して学ぶ機会を失います。
確信が持てないコードを出荷する柔軟性が失われます。
モジュールを密結合する自由が失われます。
低レベルの設計ドキュメントの作成をスキップするオプションを失います。
誰もが変更を恐れているコードに付随する安定性が失われます。
プログラマーの悩みの種である、困難で予期せぬ要件に再び焦点を当てること。テスト駆動型の開発では、既知のありふれた要件に集中する必要があり、開発はすでに想像されているものに限定されます。
考えてみれば、最終的には特定のテストケースに合わせて設計することになるので、独創的でなく、「ユーザーがX、Y、Zを実行できればいいのではないか」と考え始めることはありません。したがって、そのユーザーが潜在的なクールな要件X、Y、およびZについてすべて興奮し始めると、設計はすでに指定されたテストケースに厳格に集中しすぎて、調整が困難になる可能性があります。
もちろんこれは両刃の剣です。ユーザーが望む可能性のあるすべての考えられる、想像できる、X、Y、およびZの設計にすべての時間を費やした場合、必然的に何も完了することはありません。何かを完了すると、誰でも(自分を含む)がコード/デザインで何をしているのかを知ることができなくなります。
XMLフィードやデータベースなどの「ランダム」データのテストを作成するのは、難しくて時間がかかる場合があります(それほど難しくありません)。最近、天気データフィードの操作に少し時間を費やしました。少なくともTDDの経験があまりないので、そのためのテストを書くのはかなり混乱します。
あなたは複数の責任を持つ大きなクラスを失うでしょう。また、複数の責任を持つ大きなメソッドを失う可能性があります。リファクタリングの能力がいくらか失われる可能性がありますが、リファクタリングの必要性の一部も失われます。
Jason Cohen氏は次のように述べています。TDDには、コードに特定の組織が必要です。これはアーキテクチャ的に間違っている可能性があります。たとえば、プライベートメソッドはクラスの外部で呼び出すことができないため、メソッドをテスト可能にするには、メソッドを非プライベートにする必要があります。
私はこれが抽象化の失敗を示していると言います-プライベートコードが本当にテストされる必要があるなら、それはおそらく別のクラスにあるべきです。
デイブ・マン
アプリケーションは別の方法で作成する必要があります。それは、アプリケーションをテスト可能にする方法です。これが最初はどれほど難しいか、きっと驚くでしょう。
一部の人々は、書く前に何を書くかについて考えるという概念が難しすぎることに気づきます。モックなどの概念は、一部の人にとっても難しい場合があります。レガシーアプリのTDDは、テスト用に設計されていない場合、非常に難しい場合があります。TDDに対応していないフレームワークの周りのTDDも、苦労する可能性があります。
TDDは、ジュニア開発者が最初に苦労する可能性があるスキルです(主に彼らがこのように動作するように教えられていなかったため)。
全体的には、人々が熟練し、「臭い」コードを抽象化して、より安定したシステムを持つようになると、短所は解決されます。
すべて良い答えです。TDDのダークサイドを回避する方法をいくつか追加します。
独自のランダム化されたセルフテストを実行するアプリを作成しました。特定のテストを作成する際の問題は、多くのテストを作成しても、考えられるケースのみをカバーすることです。ランダムテストジェネレーターは、あなたが考えていなかった問題を見つけます。
多数の単体テストの概念全体は、複雑なデータ構造など、無効な状態になる可能性のあるコンポーネントがあることを意味します。複雑なデータ構造に近づかないと、テストする必要がはるかに少なくなります。
アプリケーションが許可する範囲で、通知、イベント、および副作用の適切な順序に依存する設計には気を付けてください。それらは簡単に落ちたりスクランブルされたりする可能性があるため、多くのテストが必要です。
TDDでは、コードに特定の組織が必要です。これは非効率的または読みにくい場合があります。または、アーキテクチャ的にも間違っています。たとえば、private
メソッドはクラスの外では呼び出せないため、メソッドを非公開にしてテスト可能にする必要がありますが、これは間違っています。
コードが変更されると、テストも変更する必要があります。リファクタリングでは、これは多くの追加作業になる可能性があります。
BDDの原則をTDDプロジェクトに適用すると、ここにリストされているいくつかの主要な欠点(混乱、誤解など)を軽減できることを付け加えておきます。BDDに慣れていない場合は、Dan Northの紹介を読んでください。彼は職場でTDDを適用することから生じたいくつかの問題に答えてコンセプトを思いつきました。ダンのBDDの紹介はここにあります。
BDDはこれらの欠点のいくつかに対処し、ギャップストップとして機能するため、この提案をします。フィードバックを収集する際は、この点を考慮してください。
開発時間の増加:すべてのメソッドにはテストが必要であり、依存関係のある大規模なアプリケーションがある場合は、テスト用にデータを準備してクリーンアップする必要があります。