単体テストの代わりに受け入れテストと統合テストを使用するだけで十分ですか?


62

この質問の簡単な紹介。私は現在TDDと最近BDDを1年以上使用しています。私は、モックなどの手法を使用して、テストをより効率的に記述します。最近、私は自分のために小さなお金管理プログラムを書くための個人的なプロジェクトを始めました。レガシーコードがなかったため、TDDから始めるのに最適なプロジェクトでした。残念ながら、TDDの喜びはあまり経験しませんでした。それは私の楽しみを台無しにし、プロジェクトをあきらめました。

なにが問題だったの?さて、TDDのようなアプローチを使用して、テスト/要件がプログラムの設計を進化させました。問題は、テストの作成/リファクタリングに関して、開発時間の半分以上がかかっていたことです。したがって、リファクタリングして多くのテストに書き込む必要があるため、最終的にはこれ以上機能を実装したくありませんでした。

職場では、レガシーコードがたくさんあります。ここでは、統合テストと受け入れテストを増やし、単体テストを減らしていきます。ほとんどのバグは受け入れテストと統合テストによって検出されるため、これは悪いアプローチではないようです。

私の考えは、最終的には単体テストよりも多くの統合テストと受け入れテストを書くことができるということでした。バグを検出するために言ったように、単体テストは統合/受け入れテストよりも優れていません。単体テストも設計に適しています。私はそれらの多くを書いていたので、私のクラスは常にテストしやすいように設計されています。さらに、テスト/要件が設計をガイドできるようにするアプローチは、ほとんどの場合、より良い設計につながります。単体テストの最後の利点は、高速であることです。ユニットテストとほぼ同じ速度で実行できることを知るために、十分な統合テストを作成しました。

ウェブを調べた後、私の考えによく似たアイデアがあちこちあることがわかりました。この考えをどう思いますか?

編集

質問には、デザインは良かったが、次の要件のために大規模なリファクタリングが必要な例の1つに答えました。

最初は、特定のコマンドを実行するためのいくつかの要件がありました。拡張可能なコマンドパーサーを作成しました。これは、ある種のコマンドプロンプトからコマンドを解析し、モデル上で正しいものを呼び出しました。結果は、ビューモデルクラスで表されました。 最初の設計

ここには何も問題はありませんでした。すべてのクラスは互いに独立しており、新しいコマンドを簡単に追加し、新しいデータを表示できました。

次の要件は、すべてのコマンドに独自のビュー表現(コマンドの結果の何らかのプレビュー)が必要であることです。新しい要件に対してより良い設計を実現するために、プログラムを再設計しました。 セカンドデザイン

これは、すべてのコマンドに独自のビューモデルがあり、したがって独自のプレビューがあるためです。

問題は、コマンドパーサーがコマンドのトークンベースの解析を使用するように変更され、コマンドを実行する機能が削除されたことです。すべてのコマンドには独自のビューモデルがあり、データビューモデルは、表示する必要があるデータを知っている現在のコマンドビューモデルのみを知っています。

この時点で私が知りたかったのは、新しいデザインが既存の要件を満たさなかった場合のみです。受け入れテストを変更する必要はありませんでした。ほぼすべての単体テストをリファクタリングまたは削除する必要がありましたが、これは膨大な作業の山でした。

ここで見せたかったのは、開発中によく発生する一般的な状況です。古いデザインでも新しいデザインでも問題はありませんでした。要件に応じて自然に変更されただけでした。私がどう理解したか、これはTDDの利点の1つであり、デザインが進化します。

結論

すべての答えと議論をありがとう。この議論の要約として、次のプロジェクトでテストするアプローチを考えました。

  • まず、いつものように何かを実装する前に、すべてのテストを作成します。
  • 要件については、最初にプログラム全体をテストする受け入れテストをいくつか作成します。次に、要件を実装する必要があるコンポーネントの統合テストをいくつか作成します。この要件を実装するために別のコンポーネントと密接に連携するコンポーネントがある場合、両方のコンポーネントが一緒にテストされる統合テストも作成します。最後になりましたが、アルゴリズムまたは他のクラスを高い順列(シリアライザーなど)で記述する必要がある場合は、この特定のクラスの単体テストを記述します。他のすべてのクラスはテストされませんが、単体テストが行​​われます。
  • バグについては、プロセスを簡素化できます。通常、バグは1つまたは2つのコンポーネントによって引き起こされます。この場合、バグをテストするコンポーネントの統合テストを1つ作成します。アルゴリズムに関連する場合は、ユニットテストのみを記述します。バグが発生したコンポーネントを簡単に検出できない場合、受け入れテストを作成してバグを特定します。これは例外です。


これらの質問は、なぜテストを書くのかという問題をより多く扱っているようです。単体テストの代わりに機能テストを作成する方が良いアプローチであるかどうかを議論したいと思います。
イグドラシル

私の読書ごとに、重複した質問で回答をする場合について主に -unitのテストはより多くの意味を作る
ブヨ

その最初のリンク自体は複製です。つまり、programmers.stackexchange.com
questions

Robbie Deeからのリンクからの回答は、テストする理由についてさらに詳しく説明しています。
ユグドラシル

回答:


37

オレンジとリンゴを比較しています。

統合テスト、受け入れテスト、単体テスト、動作テスト-これらはすべてテストであり、すべてコードの改善に役立ちますが、それらもまったく異なります。

私は私の意見で異なるテストのそれぞれを調べて、うまくいけばそれらのすべてのブレンドが必要な理由を説明します:

統合テスト:

単純に、システムのさまざまなコンポーネント部分が正しく統合されていることをテストします。たとえば、Webサービスリクエストをシミュレートし、結果が返されることを確認します。私は通常、実際の(っぽい)静的データとモックされた依存関係を使用して、一貫して検証できるようにします。

受け入れテスト:

受け入れテストは、ビジネスユースケースと直接相関する必要があります。それは巨大(「取引が正しく送信された」)でも、小型(「リストを正常にフィルタリングするフィルター」)でも構いません-それは重要ではありません。重要なのは、特定のユーザー要件に明示的に関連付けられる必要があるということです。テスト駆動開発ではこれらに焦点を当てるのが好きです。というのは、devとqaが検証するためのユーザーストーリーに対するテストの優れたリファレンスマニュアルがあるからです。

単体テスト:

個々のユーザーストーリーを単独で構成する場合もしない場合もあります。たとえば、特定のWebページにアクセスするとすべての顧客を取得するというユーザーストーリーは、受け入れテスト(Webのヒットをシミュレートします)ページと応答の確認)が含まれる場合もありますが、いくつかの単体テスト(セキュリティ権限が確認されていること、データベース接続が正しくクエリされていること、結果の数を制限するコードが正しく実行されていることを確認します)-これらはすべて「単体テスト」ですそれは完全な受け入れテストではありません。

行動テスト:

特定の入力の場合、アプリケーションのフローがどうあるべきかを定義します。たとえば、「接続を確立できない場合、システムが接続を再試行することを確認します。」繰り返しますが、これは完全な受け入れテストになる可能性は低いですが、それでも有用な何かを検証することができます。

これらはすべて、テスト作成の多くの経験を通じて私の意見です。教科書のアプローチに焦点を当てるのは好きではありません-むしろ、テストに価値をもたらすものに焦点を当てます。


あなたの定義では、私が意味することは、単体テストよりも多くの動作テスト(?)を書くことだと思います。私にとっての単体テストは、すべての依存関係を模擬して単一のクラスをテストするテストです。単体テストが最も役立つ場合があります。たとえば、複雑なアルゴリズムを書くときです。次に、アルゴリズムの期待される出力を含む多くの例を示します。実際に動作テストよりも高速であるため、ユニットレベルでこれをテストする必要があります。動作テストで簡単にテストできるクラスを通るパスのみを手に持っているユニットレベルでクラスをテストする価値はありません。
イグドラシル

14
私は個人的に受け入れテストは、最も重要なコミュニケーションのようなものをテストするときに、行動試験が重要である小さな複雑な機能をテストするときに、信頼性とエラーケースとユニットテストが重要である(これのアルゴリズムは次のようになります良い例)だと思う
マイケル・

私はあなたの専門用語にそれほど自信がありません。プログラミングスイートをプログラムします。そこでは、グラフィカルエディターを担当しています。スイートの残りの部分からの模擬サービスと模擬UIを使用してエディターをテストする私のテスト。それはどのようなテストでしょうか?
イグドラシル

1
テスト対象に依存します-ビジネス機能をテストしていますか(受け入れテスト)。統合をテストしていますか(統合テスト)?ボタンをクリックすると何が起こるかをテストしていますか(動作テスト)?アルゴリズムをテストしていますか(単体テスト)?
マイケル

4
「教科書のアプローチに焦点を当てるのは好きではありません-むしろ、あなたのテストに価値を与えるものに焦点を合わせてください」ああ、そう本当です!常に最初に尋ねる質問は、「これを行うことでどのような問題を解決できますか?」です。また、プロジェクトごとに解決すべき問題が異なる場合があります。
ローランブルゴーロイ

40

TL; DR:それがあなたのニーズを満たす限り、はい。

私は何年も前から受け入れテスト駆動開発(ATDD)開発を行ってきました。それは非常に成功する可能性があります。知っておくべきことがいくつかあります。

  • ユニットテストは、IOCの実施に本当に役立ちます。単体テストがなければ、開発者は適切に作成されたコードの要件を満たしていることを確認する責任があります(単体テストが適切に作成されたコードを実行する限り)
  • 通常はモックされているリソースを実際に使用している場合、速度が遅くなり、誤った障害が発生する場合があります。
  • このテストでは、単体テストのように特定の問題を特定することはしません。テストの失敗を修正するには、さらに調査する必要があります。

今の利点

  • テスト範囲が大幅に改善され、統合ポイントがカバーされます。
  • システム全体が、ソフトウェア開発の全ポイントである受け入れ基準を満たしていることを確認します。
  • 大規模なリファクタリングをはるかに簡単、高速、安価にします。

いつものように、分析を行い、このプラクティスがあなたの状況に適切かどうかを判断するのはあなた次第です。多くの人とは異なり、理想的な正しい答えはないと思います。それはあなたのニーズと要件に依存します。


8
素晴らしい点。テストについて少し専門的な知識を身に付け、何百ものケースを書いて、色が飛んで「合格」したときに温かい満足感を得るのは非常に簡単です。簡単に言うと、ソフトウェアがユーザーの観点から必要なことを実行しない場合、最初で最も重要なテストに失敗します。
ロビーディー

特定の問題を特定するのに適しています。巨大な要件がある場合は、システム全体をテストする受け入れテストを作成し、システムの特定のコンポーネントのサブタスクをテストして要件を達成するテストを作成します。これにより、ほとんどの場合、欠陥が存在するコンポーネントを特定できます。
Yggdrasil

2
「ユニットテストはIOCの実施に役立つ」?!?IoCの代わりにDIを意味すると思いますが、とにかく、誰かがDIの使用を強制したいのはなぜですか?個人的には、実際にはDIは非オブジェクト(プロシージャルスタイルのプログラミング)につながることがわかります。
ロジェリオ

統合と単体テストの両方を実行する(IMO最適)オプションと、統合テストのみを実行するという議論について意見を述べてください。ここでのあなたの答えは良いですが、これらのことを相互に排他的であると考えているようです。
スターマンデラックス

@starmandeluxeこれらは実際、相互に排他的ではありません。むしろ、テストから導き出す価値の問題です。値が単体テストを作成するための開発/サポートコストを超える場所であればどこでも単体テストを行います。例 確かに、金融アプリケーションで複利関数を単体テストします。
-Dietbuddha

18

さて、TDDのようなアプローチを使用して、テスト/要件がプログラムの設計を進化させました。問題は、テストの作成/リファクタリングに関して開発時間の半分以上がかかっていたことです

単体テストは、使用するコンポーネントのパブリックインターフェイスがあまり頻繁に変更されない場合に最適に機能します。これは、コンポーネントがすでに適切に設計されている場合(たとえば、SOLID原則に従って)を意味します。

したがって、コンポーネントで多くの単体テストを「スロー」することから「進化」するだけで良いデザインを信じることは誤りです。TDDは優れた設計の「教師」ではありません。設計の特定の側面が優れていること(特にテスト容易性)を検証するのに少しだけ役立ちます。

要件が変更され、コンポーネントの内部を変更する必要がある場合、これによりユニットテストの90%が中断されるため、非常に頻繁にリファクタリングする必要があり、デザインはおそらくあまり良くありませんでした。

したがって、私のアドバイスは次のとおりです。作成したコンポーネントの設計、およびオープン/クローズの原則に従ってコンポーネントをさらに作成する方法について考えてください。後者の考え方は、コンポーネントを変更せずに後でコンポーネントの機能を拡張できるようにすることです(したがって、ユニットテストで使用されるコンポーネントのAPIを壊すことはありません)。このようなコンポーネントは単体テストテストでカバーすることができます(カバーする必要があります)。また、経験はあなたが説明したほど苦痛ではありません。

そのような設計をすぐに思いつかない場合は、受け入れテストと統合テストの方が良いスタートになるかもしれません。

編集:コンポーネントの設計は問題ない場合もありますが、単体テストの設計が問題を引き起こす可能性があります。簡単な例:クラスXのメソッド "MyMethod"をテストして記述したい

    var x= new X();
    Assert.AreEqual("expected value 1" x.MyMethod("value 1"));
    Assert.AreEqual("expected value 2" x.MyMethod("value 2"));
    // ...
    Assert.AreEqual("expected value 500" x.MyMethod("value 500"));

(値には何らかの意味があると仮定します)。

さらに、実稼働コードではの呼び出しが1回だけであると想定しX.MyMethodます。現在、新しい要件のために、メソッド "MyMethod"には追加のパラメーター(例:などcontext)が必要ですが、これは省略できません。単体テストがなければ、呼び出しコードを1か所でリファクタリングする必要があります。単体テストでは、500箇所をリファクタリングする必要があります。

しかし、ここでの原因は単体テスト自体ではなく、「X.MyMethod」への同じ呼び出しが「Do n't Repeat Yourself(DRY)」の原則に厳密に従っていないという事実だけです。ここでは、テストデータと関連する期待値をリストに入れ、「MyMethod」の呼び出しをループで実行します(または、テストツールがいわゆる「データドライブテスト」をサポートしている場合、その機能を使用します)。メソッドシグネチャが1(500ではなく)に変更されたときにユニットテストで変更する場所の数。

実際の場合、状況はもっと複雑かもしれませんが、アイデアが得られることを願っています-ユニットテストで、変更される可能性があるかどうかわからないコンポーネントAPIを使用する場合は、必ず数を減らしてくださいそのAPIの呼び出しの最小値。


「これは、コンポーネントが既によく設計されている場合、意味します。」:私はあなたに同意していますが、コードを書く前にテストを書く場合はどのコンポーネントが既に設計することができ、かつコードがあるデザインは?少なくともこれがTDDの理解方法です。
ジョルジオ

2
@Giorgio:実際には、最初にテストを書くのか、後でテストを書くのかは問題ではありません。設計とは、コンポーネントの責任、パブリックインターフェイス、依存関係(直接または挿入)、実行時またはコンパイル時の動作、可変性、名前、データフロー、制御フロー、レイヤーなどについて決定することです。また、設計とは、いくつかの決定を可能な限り最新の時点まで延期することを意味します。ユニットテストでは、設計が正常であるかどうかを間接的に示すことができます。要件が変更されたときに、それらの多くを後でリファクタリングする必要がある場合は、おそらくそうではありません。
Doc Brown

@Giorgio:例が明確になるかもしれません:メソッド "MyMethod"と2つのパラメーターを持つコンポーネントXがあるとします。TDDを使用してX x= new X(); AssertTrue(x.MyMethod(12,"abc"))、メソッドを実際に実装する前に記述します。事前設計を使用して、class X{ public bool MyMethod(int p, string q){/*...*/}}最初に記述し、後でテストを記述できます。どちらの場合も、同じ設計上の決定を下しています。決定が良かったり悪かった場合、TDDはあなたに知らせません。
ドックブラウン

1
私はあなたに同意します:TDDが自動的に良いデザインを生成するという仮定でTDDが盲目的に適用されるのを見ると、私は少し懐疑的です。さらに、デザインがまだ明確でない場合、TDDが邪魔になることがあります。自分がやっていることの概要を理解する前に、詳細をテストすることを余儀なくされます。したがって、私が正しく理解していれば、同意します。(1)単体テストは設計の検証には役立ちますが、設計は独立したアクティビティであり、(2)TDDは常に最適なソリューションではないため、テストの記述を開始する前にアイデアを整理する必要があり、TDDが遅くなる可能性があると思いますこの。
ジョルジオ

1
まもなく、単体テストはコンポーネントの内部設計に欠陥を示す可能性があります。インターフェイス、事前条件、事後条件を事前に知っておく必要があります。そうでない場合は、単体テストを作成できません。そのため、単体テストを作成する前に、コンポーネントが行うコンポーネントの設計を実行する必要があります。これを行う方法-下位レベルのデザイン、詳細なデザイン、内部のデザイン、またはあなたがそれを呼びたいものは何でも-はユニットテストが書かれた後に行われます。
マールテンボデウェス14年

9

はい、もちろんです。

このことを考慮:

  • 単体テストは、小さなコードを実行する小さなターゲットテストです。適切なコードカバレッジを実現するためにそれらの多くを書くので、すべて(または厄介なビットの大部分)がテストされます。
  • 統合テストは、コードの大部分を実行するテストの大規模で幅広い部分です。適切なコードカバレッジを達成するためにそれらのいくつかを記述して、すべて(または厄介なビットの大部分)がテストされるようにします。

全体的な違いをご覧ください。

この問題はコードカバレッジの1つです。統合/受け入れテストを使用してすべてのコードの完全なテストを達成できれば、問題はありません。コードがテストされます。それが目標です。

すべてのユニットが実際に連携して動作することを確認するために、すべてのTDDベースのプロジェクトに何らかの統合テストが必要になるため、それらを混同する必要があると思いますそれらをすべてまとめると!)

問題は、テスト、障害のデバッグ、およびそれらの修正の容易さにあります。一部の人々は、単体テストがこれに非常に優れていると感じています。小さくてシンプルで、失敗が見やすいですが、欠点は、ユニットテストツールに合わせてコードを再編成し、それらの多くを書く必要があることです。統合テストは、多くのコードをカバーするために書くのがより難しく、おそらくロギングなどの手法を使用して障害をデバッグする必要があります(ただし、とにかくこれを行う必要があると思いますが、障害を単体テストすることはできませんオンサイト!)。

どちらにしても、テスト済みのコードが得られるので、どちらのメカニズムがより適しているかを判断するだけです。(少しミックスして、複雑なアルゴリズムの単体テストを行い、残りを統合テストします)。


7
まったくそうではありません...統合テストでは、両方ともバグのある2つのコンポーネントを使用できますが、それらのバグは統合テストでキャンセルされます。また、エンドユーザーは、これらのコンポーネントの一つだけが使用される方法でそれを使用するまでは...たいしたない
マイケル・ショー

1
コードカバレッジ!=テスト済み-バグが互いにキャンセルし合うことは別として、今まで考えたことのないシナリオについてはどうでしょうか。統合パステストは、ハッピーパステストには適していますが、うまくいかない場合、適切な統合テストはほとんど見られません。
マイケル

4
@Ptolemy 2つのバグのあるコンポーネントが互いに打ち消し合うことはまれであり、2つのコンポーネントが互いに干渉するよりもはるかに低いと思います。
gbjbaanb 14年

2
@Michaelの場合、テストに十分な労力を注いでいません。テストをより詳細に行う必要があるため、適切な統合テストを行うのは難しいと言いました。統合テストでは、単体テストと同じくらい簡単に不良データを提供できます。統合テスト!=ハッピーパス。できる限り多くのコードを実行することについてです。そのため、どのくらいのコードが実行されたかを示すコードカバレッジツールがあります。
gbjbaanb 14年

1
@Michael CucumberやSpecFlowなどのツールを正しく使用すると、統合テストを作成できます。統合テストでは、例外や極端な状況も単体テストと同じ速さでテストできます。しかし、1つのクラスに多くの順列が必要な場合、このクラスの単体テストを作成することを好みます。しかし、これは、少数のパスのみを含むクラスを使用する場合よりも頻繁ではありません。
イグドラシル

2

それは恐ろしいアイデアだと思います。

受け入れテストと統合テストは、特定のターゲットをテストするためにコードのより広い部分に触れるため、それらは少なからず、より多くのリファクタリングを必要とします。さらに悪いことに、これらはコードの広範なセクションをカバーしているため、より広い範囲の検索対象があるため、根本原因の追跡に費やす時間が増加します。

いいえ、90%UIなどの奇妙なアプリや、単体テストでは扱いにくい他のアプリがない限り、通常は単体テストをもっと書く必要があります。あなたが直面している痛みは、単体テストではなく、テストを最初に開発することです。一般的に、ほとんどのライティングテストでは、時間の3分の1しか費やすべきではありません。結局のところ、彼らはあなたに奉仕するためにそこにいますが、その逆ではありません。


2
TDDに対して私が耳にする主な牛肉は、自然な開発フローを混乱させ、最初から防御的なプログラミングを実施することです。プログラマーがすでに時間的なプレッシャーにさらされている場合、彼らは単にコードをカットし、後で磨きたいと思うでしょう。もちろん、バグのあるコードで任意の期限を守ることは、誤った経済です。
ロビーディー

2
確かに、特に「後でそれを磨く」ことは実際には起こらないようです-私が行うすべてのレビューは、開発者が「外出する必要があり、後でそれを行う」ことを知っていますが、それは起こりません-テクニカル借金=私の意見では破産した開発者。
マイケル

3
答えは私には理にかなっています、なぜそれほど多くのマイナスを得たのか分かりません。Mike Cohnの言葉を引用すると、「単体テストは堅実なテスト自動化戦略の基盤であり、それ自体がピラミッドの最大の部分を占めています。自動化された単体テストはプログラマに特定のデータを提供するため、すばらしいものです。ライン47" mountaingoatsoftware.com/blog/...
guillaume31

4
@ guillaume31ある人が一度彼らが良いと言ったからといって、彼らが良いとは限りません。私の経験では、バグは事前に新しい要件に変更されているため、単体テストでは検出されません。また、ほとんどのバグは統合バグです。そのため、統合テストでそれらのほとんどを検出します。
イグドラシル

2
@Yggdrasilマーティン・ファウラーも引用できます。「高レベルのテストで障害が発生した場合、機能コードにバグがあるだけでなく、ユニットテストもありません」。martinfowler.com/bliki/TestPyramid.htmlとにかく、もし統合テストだけがあなたのために働くなら、それでいいです。私の経験では、必要なものの、ユニットテストよりも遅く、正確性の低い障害メッセージを提供し、操作性が劣ります(より組み合わせやすい)。また、統合テストを作成するとき、オブジェクト自体の正確さではなく、事前に(誤った)考えられたシナリオについて推論することで、将来に対する保証が少なくなる傾向があります。
guillaume31

2

TDDの「メリット」は、テストが記述されると、テストを自動化できることです。逆に、開発時間のかなりの部分を消費する可能性があります。これが実際にプロセス全体の速度を低下させるかどうかは議論の余地があります。引数は、事前テストにより、開発サイクルの終了時に修正されるエラーの数が減ることです。

ユニットテストに動作を含めることができるため、ここでBDDが使用されます。そのため、定義上、プロセスは抽象的ではなく具体的​​になります。

明らかに、無限の時間が利用可能であれば、さまざまな種類のテストを可能な限り多く行うことになります。ただし、一般的に時間は限られているため、継続的なテストはある程度の費用効果があります。

これはすべて、最も価値のあるテストをプロセスの先頭に置くべきだという結論につながります。これ自体では、あるタイプのテストが別のタイプよりも自動的に優先されるわけではありません。それぞれのケースでメリットを考慮しなければなりません。

個人用のコマンドラインウィジェットを作成している場合、主に単体テストに関心があります。一方、Webサービスでは、かなりの量の統合/動作テストが必要になります。

ほとんどのタイプのテストは「レーシングライン」と呼ばれるもの、つまり今日のビジネスに必要なもののテストに集中しますが、ユニットテストは後の開発フェーズで表面化する可能性のある微妙なバグを取り除くのに優れています。これは容易に測定できない利点であるため、しばしば見落とされます。


1
私は自分のテストを前もって書き、ほとんどのエラーをカバーするのに十分なテストを書きます。後で表面化するバグについて。これは、要件が変更されたか、新しい要件が適用されるように思えます。統合/動作テストよりも変更する必要がある、追加されました。その後、古い要件にバグが表示された場合、このテストでバグが表示されます。自動化に関しては。すべてのテストが常に実行されます。
Yggdrasil

最後の段落で考えていた例は、たとえば、ライブラリが単一のアプリケーションによって排他的に使用されていたが、それを汎用ライブラリにするためのビジネス要件があったということです。この場合、ライブラリに接続するすべてのシステムについて、新しい統合/動作テストを作成するよりも、少なくともいくつかのユニットテストを行う方が役立つ場合があります。
ロビーディー

2
テストの自動化と単体テストは完全に直交する問題です。自尊心のあるプロジェクトでは、自動化された統合と機能テストが行​​われます。確かに、手動の単体テストはあまり見られませんが、存在する可能性があります(基本的に、手動の単体テストは特定の機能のテストユーティリティです)。
-Jan Hudec

まあ確かに。かなりの期間、開発分野の外に存在する自動化されたサードパーティツールの市場が繁栄してきました。
ロビーディー

1

単体テストの最後の利点は、高速であることです。ユニットテストとほぼ同じ速度で実行できることを知るために、十分な統合テストを作成しました。

これが重要なポイントであり、「最後の利点」だけではありません。プロジェクトがますます大きくなると、統合受け入れテストはますます遅くなります。そして、ここで、私はあなたがそれらの実行を停止しようとしているほど遅いことを意味します。

もちろん、単体テストも遅くなりつつありますが、それでも桁違いに高速です。たとえば、以前のプロジェクト(c ++、約600 kLOC、4000個のユニットテスト、200個の統合テスト)では、統合テストの実行に15分以上かかったのに約1分かかりました。変更するパーツの単体テストを構築して実行するには、平均で30秒もかかりません。あなたがそれをとても速くすることができるとき、あなたはいつもそれをしたいと思うでしょう。

明確にするために:統合テストと受け入れテストを追加しないとは言いませんが、TDD / BDDを間違った方法で行ったようです。

単体テストも設計に適しています。

はい、テスト容易性を念頭に置いて設計すると、設計が改善されます。

問題は、テストの作成/リファクタリングに関して、開発時間の半分以上がかかっていたことです。したがって、リファクタリングして多くのテストに書き込む必要があるため、最終的にはこれ以上機能を実装したくありませんでした。

まあ、要件が変わると、コードを変更する必要があります。単体テストを作成しなかった場合、作業を終了しなかったことを伝えます。しかし、これはユニットテストで100%をカバーする必要があるという意味ではありません-それは目標ではありません。いくつかのこと(GUIやファイルへのアクセスなど)は、ユニットテストすることさえ意図されていません。

この結果、コードの品質が向上し、テストの別のレイヤーができます。価値があると思います。


また、数千の受け入れテストもあり、すべてを実行するには1週間かかりました。


1
私の例を見てみましたか?これは常に起こりました。重要なのは、新しい機能を実装するとき、ユニットテストを変更/追加して、新しい機能をテストするようにすることです。したがって、ユニットテストは中断されません。ほとんどの場合、環境が模擬されているため、単体テストでは検出されない変更の副作用があります。私の経験では、これまで単体テストで既存の機能が壊れているとは言われませんでした。私の間違いを示したのは、常に統合テストと受け入れテストでした。
ユグドラシル14年

実行時間は。アプリケーションの成長に伴い、ほとんどの孤立したコンポーネントが増えています。そうでない場合、私は何か間違ったことをしました。私が新しい機能を実装するとき、それはほとんど限られた数のコンポーネントにしかありません。アプリケーション全体の範囲で1つ以上の受け入れテストを作成しますが、時間がかかる可能性があります。さらに、コンポーネントの観点から同じテストを作成します。コンポーネントは通常高速なので、このテストは高速です。コンポーネントテストは十分に高速なので、いつでもコンポーネントテストを実行できます。
イグドラシル14年

@Yggdrasil既に述べたように、単体テストはすべてが強力というわけではありませんが、最も高速であるため、通常はテストの最初の層です。他のテストも有用であり、組み合わせる必要があります。
BЈовић

1
それらが高速だからといって、これが理由で使用されるべきだとか、それらを書くのが一般的だからという意味ではない。私が言ったように、私のユニットテストは壊れません-したがって、それらは私にとって価値がありません。
イグドラシル

1
問題は、それらが壊れていない場合、単体テストからどのような価値がありますか?常に新しい要件に合わせて調整する必要があるのに、なぜそれらを書くのが面倒ですか?私が見るそれらからの唯一の値は、高い順列を持つアルゴリズムと他のクラスのためです。しかし、これらはコンポーネントおよび受け入れテストよりも少ないです。
Yggdrasil 14年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.