web-dev-qa-db-ja.com

単体テストが不適切または不要なのはいつですか?

(少なくともStack Overflowでは)常にユニットテストが必要であり、常に最新の状態に保つ必要があると一般的に想定されているようです。しかし、私はこれらのアサーションを作成するプログラマーが私とは異なる種類のプロジェクトで動作するのではないかと疑っています。

それがユニットテストが最も価値のあるスペクトルの終わりである場合、他の目的は何ですか?単体テストの価値が最も低いのはどこですか?どのような状況で気になりませんか?テストを維持する努力がコストに見合わないのはどこでしょうか?

109
Steve Bennett

個人的には、次のような状況の単体テストは記述しません。

  1. コード 枝がない ささいなことです。 0を返すゲッターはテストする必要がなく、変更はそのコンシューマーのテストでカバーされます。

  2. コードは単に安定したAPIに渡されます。標準ライブラリが適切に動作すると仮定します。

  3. コードは他のデプロイされたシステムと相互作用する必要があります。次に、統合テストが必要です。

  4. 成功/失敗のテストが、ステガノグラフィが人間に気付かれないように、確実に測定できないほど定量化することが非常に難しい場合。

  5. テスト自体がコードよりも作成が1桁難しい場合。

  6. コードが使い捨てまたはプレースホルダーコードの場合。疑問がある場合は、テストしてください。

107
Telastyn

テストせずにコードを書く場合を除いて、常にテストのコストが発生します。

単体テストがある場合とない場合の違いは、手動でテストする場合のコストと比較した、テストを作成するコストと実行するコストの違いです。

単体テストを作成するコストが2分で、単体テストを実行するコストが実質的に0であるが、コードを手動でテストするコストが1分の場合、テストを2回実行しても中断します。


何年もの間、コードの単体テストを作成するのに十分な時間がないという誤解を受けていました。私がテストを書いたとき、それらは肥大化した重いものであり、ユニットテストを書くべきだと思うようになっただけですknew必要なときだけです。

最近、私は Test Driven Development を使用するよう勧められましたが、それは完全な啓示であることがわかりました。時間がないと確信しましたnot単体テストを作成する

私の経験では、テストを念頭に置いて開発することで、よりクリーンなインターフェイス、より焦点を絞ったクラスとモジュール、そして一般的にはより多くの [〜#〜] solid [〜#〜] 、テスト可能なコードが得られます。

ユニットテストのないレガシーコードで作業し、手動で何かをテストする必要があるときはいつも、「このコードにユニットテストがすでにあると、はるかに速くなる」と考え続けます。結合度の高いコードに単体テスト機能を追加しようとするたびに、「分離された方法で記述されていれば、これはずっと簡単になる」と考え続けます。

私がサポートしている2つの実験ステーションを比較対照しています。 1つはしばらくの間存在し、多くのレガシーコードがあり、もう1つは比較的新しいものです。

古いラボに機能を追加する場合、多くの場合、ラボに行き、必要な機能の影響を調査するために何時間も費やし、他の機能に影響を与えずにその機能を追加する方法を説明します。コードはオフラインテストを許可するように設定されていないため、ほとんどすべてをオンラインで開発する必要があります。オフラインで開発しようとすると、妥当な数よりも mock objects になってしまいます。

新しいラボでは、通常、デスクでオフラインで開発し、すぐに必要なものだけをモックアウトして、ラボで短時間だけ過ごすことで機能を追加し、拾い上げられなかった残りの問題を解決することができます。 -ライン。


TL; DR バージョン:

テストを作成するコストに加えて、必要な回数だけテストを実行するコストは、必要な回数だけ手動でテストするコストよりも少ない場合に、テストを作成します。

ただし、TDDを使用する場合、テストを作成するコストは、それが上手くなるにつれて低下する可能性が高く、コードが完全に自明でない限り、おそらく予想よりも頻繁にテストを実行することになります。

77
Mark Booth

単体テストを作成するコストとそれらが追加する価値の間にはトレードオフがあります。これを怠ると 過剰テスト の可能性があります。

blueberryfields 単体テストの値に影響を与える1つの変数、つまりプロジェクトの安定性(または開発のペース)に触れました。拡大したいのですが。

単体テストの価値は、おおよそ次のプロットに従います(そう、MSペイント!)。

utility vs stability

  1. 最初のゾーンでは、コードが不安定なため、ユニットテストを書き換えたり、完全に廃棄したりする必要がよくあります。これは、使用されないことがわかっているプロトタイプである可能性があります。または、プログラミング言語またはフレームワークに慣れていないプロジェクトである場合もあります(多くの場合、大量のコードをやり直す必要があります)。

    ユニットテストは、モジュールレベルでのリファクタリング(つまり、関数の変更)に適しています。問題は、コードがアーキテクチャレベルで不安定であり、モジュール全体が書き換えられたり、削除されたり、完全に再設計されたりする場合です。その後、単体テストを変更/削除/追加する必要があり、これは負担になります。

    この段階では、システムレベルの統合テスト、または手動テストに制限することをお勧めします(どちらを選択するかは、テストを作成するコストと得られる値に依存します)。

  2. ユニットテストは、2番目のゾーンに最大値を追加します。コードは、モジュールレベルより上になりますが、まだ安定していません )atモジュールレベル。安定したコードベースがあり、滞在する可能性が高いモジュールを追加する場合は、ユニットテストが大きな成功を収めるのはこのときです。

  3. ユニットテストは、テスト中のコードの安定性が非常に高い場合にも、価値が低くなります。標準ライブラリ関数の単純なラッパーをテストすることは、単体テストがやり過ぎである1つの例です。

    作成しているコードの一部を変更する必要がない可能性が高く、正しく機能していると確信している場合(多分それは非常に単純ですか?)、テストする価値が少なくなります。

以下のゾーンIIのグラフに示すように、ユーティリティがコストよりも大きい場合、単体テストは有益になります。

utility and cost

このコストラインは、人によってレベルが異なる可能性があります(ライン1とライン2)。プロジェクトで使用されているテストフレームワークを初めて使用する場合は、これによりレベルが上がり、netユーティリティが少なくなります。より高いコスト(2行目)は、単体テストが適切である範囲を狭めます。

コストラインは必ずしもフラットである必要はありません。特に、プロジェクトサイズなどの他の変数を検討する場合、およびプロジェクトのテストフレームワークがすでに存在するかどうかは、そうなる可能性があります。

21
jakesandlund

個人的に、私は通常、以下のユニットテストを記述しません。

  • 既存の単体テストされていない(レガシー)コードへの変更理論的には単体テストを開始するのに遅すぎることはありませんが、実際には、TDDされなかったコードに単体テストを追加することによる利益はわずかです。唯一の利点は、退行防止です。変更の影響が予想される領域と予想されない領域にどのような影響があるかを確認できます。ただし、単体テストは、テストを記述したときと同じようにコードが機能することを証明するだけです。テストは元の要件に基づいて記述されていないため、テストは現在の実装が「正しい」ことを証明しません。このようなコードベースに単体テストの変更を加えることは、私の経験ではさらに悪夢のようなものであり、単純に変更を加えて、プログラムの影響を受ける領域を手動で実行します。問題のコードの適切な単体テストを作成する必要があります(モックおよびその他のTDDに適したアーキテクチャを可能にするためにコードをリファクタリングする必要がある場合があります)、合格し、かつリファクタリングが何も壊れていないことを証明します(これが100万LoCコードベース用に作成された最初の単体テストは難しい場合があります)、テストを変更して別のことを期待し、コードを変更して変更されたテストに合格します。

  • Iレイアウトとトップレベルの動作。場合によっては、それは単に実現不可能です。 「デザイナ」を持つ多くのIDEは、UI要素をプライベートとして宣言し、概念的にパブリックであってはなりません。それらを内部にするには、ユニットテストを本番コードと同じアセンブリに配置する必要があり(悪い)、保護する場合は、コントロールについて知る必要があるものを公開する「テストプロキシ」が必要です(これも通常は行われません)。すべてのコントロールをパブリックにして、そのタイプ、位置、フォーマットプロパティなどにアクセスすることが許容されたとしても、UIが期待どおりに設計されていることを確認するテストは非常に脆弱です。通常は、コードビハインド/ビューモデルでイベントハンドラーを単体テストすることができ、ボタンをクリックするとハンドラーが起動することを証明するのは簡単です。

  • データベースの永続性。これは、定義上、統合テストです。リポジトリにデータを渡すコードを処理するときは常にリポジトリをモックし、リポジトリ自体の内部で開発するときはORMのフックをモックします。 「データベースの単体テスト」があり、SQLiteのようなものを使用してデータベースを「模擬」することができますが、これらのテストはユニットレベルではまったく適合しないことがわかりました。

  • サードパーティコード。あなたは自分のコードを好きなようにテストし、使用しているサードパーティツールの開発者(WPF、WCF、EFなどの.NET Framework自体のコンポーネントを含む)が正しく機能することを証明します。正しいWCF呼び出しを行ったことを証明する単体テストでは、実際にサービスプロキシを通過する必要はありません。また、単体テストで特定のWCFサービス呼び出しが正しく機能することをテストする必要はありません(機能するかどうかは、ローカルのテスト環境では完全であるがビルドボットでは完全ではない可能性がある環境固有の変数に依存するか、QA、ステージング、またはUAT環境に依存します。レベル統合、AAT、手動テストはまだ価値があります)。

他のほとんどすべてのケースで、テストファーストの方法論は、要件とYAGNIの適用、回帰の防止、要件の競合の特定などに大きな価値があります。「重要な」コードの場合でも、「はい、このプロパティはまだこれを返します」という検証価値があるので、あなたは他のテストでそれを信頼できる」と開発者として私に価値があります。

21
KeithS

単体テストの価値が最も低いのはどこですか?

論理コードのみの単体テストを作成する必要があります。論理コードの定義は以下のとおりです。

論理コードは、ある種のロジックが含まれているコードの一部であり、それは小さいかもしれません。 IFステートメント、ループ、switchまたはcaseステートメント、計算、またはその他のタイプの意思決定コードが1つ以上ある場合は、論理コードです。

それがユニットテストが最も価値のあるスペクトルの終わりである場合、他の目的は何ですか?

  • 密結合コードは簡単にテストできません。時にはそれはまったくテストすることができません。たとえば、 ASP.NET Webフォームは、ユニットテストを念頭に置いて構築された ASP.NET MVC とは対照的に、悪夢であり、テストが不可能な場合があります。

  • 私は、非常に小さく単純なプロジェクトのテストを記述しないことを選択する場合があります。これは、時間とリソースが限られている世界では完全に正当化できます。はい、それは危険ですが、あなたが働いている会社が市場に出す時間が限られている場合、それは完全に受け入れられます。

あなたが気にしないどんな状況ですか?テストを維持する努力がコストに見合わないのはどこでしょうか?

ユニットテストが実施されると、メンテナンスコストは非常に小さくなります。高いコードカバレッジでの単体テストは、システムが期待どおりに動作するという貴重な自信を与えます。同じことが統合テストにも当てはまりますが、それはあなたの質問ではありません。

私の答えは次の仮定に基づいています:

  • 単体テスト、統合テスト、機能テストの違いを知っています。
  • ユニットテストフレームワークの1つに習熟しているため、ユニットテストを作成するのにほとんど労力を要しません。
  • 単体テストを作成しているときに、余分な作業をしているように感じることはありません。

参照:Art of Unit Testing

11
CodeART

ケントベック(ユニットテストのアイデアの背後にある男) says 捨てる可能性のあるアイデア(たとえば、プロトタイプ)で作業するときにユニットテストを記述しないことは問題ない(作業しないと決めた場合)これより先)。それどころか、プロトタイプを作成してそれを採用することに決めた場合、ユニットテストは前の回答で取り上げたすべての理由で役立ちます。

9
sakisk

実際には、2回以上実行するコードのテストが必要です。

一度実行して破棄する場合は、テストが役に立たない可能性がありますが、ドメインが複雑な場合は、テストを記述して、設計と実装に役立てることができます。

そうでない場合、テストが行​​うことは、仮定がまだ正しいことを確認することだけである場合でも、価値があります。また、複数のセッションが続くコードには変更が必要になります。その時点で、テストは10倍の費用がかかります。

7
Bill Michell

私は不必要についての手がかりはありませんが、ユニットテストが不適切であると思われる場合は、比例的なメリットなしにコストを追加するという点で狙います。

私たちの組織/開発チームがユニットテストを行っていない場合は、他の開発者にユニットテストの実行、修正(そして自分で作成すること)を納得させることができなければ、作成したテストは実行されません。そして維持。 (これは、あなたが誰かと一緒にソフトウェアの一部で作業していることを意味します。)

誰もがユニットテストを行っているわけではありません。ローカルチームのカルチャーによって厳格にサポートされていることがあります。そのような環境では、まず大多数の開発者とおそらくビルドプロセス(「[継続的]統合」)のためにもそれらを配置する必要があります。 )実際にユニットテストを書き始める前は理にかなっています。

時間のプレッシャーと納期、およびチームとの「自分の」相対的な立場を考えると、単体テストを作成するのに意味があるまでの残り時間は、数か月または数年になりがちです。

6
Martin Ba

場合によっては、単体テストを行う時間がないことがあります。大丈夫。

外部の制約が存在し、システム全体の状態をしっかりと把握し、変更がどのように波及するかを理解しているため、特定の瞬間にテストの必要性を感じない場合があります。それ。

しかし、私はあなたがそれについて少し有罪を感じるをすべきだとまだ信じています。 "ああ、ええ、私はものをテストしていないので、テストを始めましょう。"

その瞬間の前に、罪悪感は後でコードテストを自動化することを妨げる特定のアーキテクチャの選択を回避するのに役立ちます。

4
ZJR

コストはテストを維持することではなく、動作するコードを維持しないことです。テストと実装を離婚した場合、あなたが書いたものは証明の恩恵なしに機能すると想定しています。テストは、その証拠と、時間の経過とともにコードを維持する自信を与えます。使い捨てだと思ったアプリに再びアクセスすることはないと思うかもしれませんが、実際には、ソフトウェアの作成に費やす時間はすべて、雇用主が軽視したくない投資です。それに直面しよう、ソフトウェア開発者は一般的に安くは来ません、そしてコードを捨てるために費やされた時間は単にあなたの雇用主に燃やされたお金です。

問題が急増している場合、数行のコードを記述して動作を確認する場合、または単にProgrammers.SEの例をまとめている場合は、実際には、満足したときに完全に破棄する予定の何かを作成する場合です。問題のあなたの理解。このような場合、単体テストはタスクの妨げになる可能性があり、安全に除外できます。ただし、他のすべてのケースでは、プログラムが比較的重要ではないと思われる場合でも、テストは常に適切であり、常に十分なテストサポートを備えた専門的な標準にソフトウェアを記述し、コードを未来。

2
S.Robins

プロジェクトで行われる単体テストの量と品質は、開発のペースと製品に必要な安定性に正比例します。

一方では、1回限りのスクリプト、簡単なデモ、または非常に早い段階でのペースの速い起動環境では、ユニットテストが重要であり、何にでも役立つ可能性はほとんどありません。それらはほとんど常に、ほぼ確実に、時間とリソースの浪費です。

反対に、ペースメーカーやパイロットのロケット船を制御するソフトウェアを書くとき、または安定した非常に複雑なソフトウェアシステム(たとえば、マルチバース全体で多く採用されているコンパイラ)の単体テストの複数の層を維持するために作業するとき、および他の報道は重要です。

[チームの規模、予算、開発者の才能、好みのソフトウェア開発戦略など、他の状況固有の要因がたくさんあります。一般的に、最高レベルの抽象化、これら2つが最大の違いを生むことがわかります]

1
blueberryfields

私の考えでは、製品/コードのプロトタイプは、完成品とはまったく異なるプロセスを使用して、まったく異なる目的で提供されることが多いため、テストは必要ありません。

この一般的なシナリオを想像してみてください。あなたの会社が有名なある種のテクノロジーがあり、営業チームまたは最高経営責任者がクライアントに行って、あなたのテクノロジーを活用している別の製品を彼らに販売することができます。彼らはそこで販売し、1か月後にベータ版が表示されることをクライアントに約束します。開発チームでさえ、何もありません。

次に何が起こるかは、クライアントに同意/販売されたポイントに基づいてソリューションをすばやく設計し、(多くの場合はスターの)エンジニアのチームを編成して、コードの記述を開始することです。もちろん、日付がずれておらず(常にずれている)、4週間ではなく3週間でコードを書くことができれば理想的です。この場合、1週間余分にあり、今週のQAチームの時間を確保できた場合は、テストします。実際には、追加の1週間はなく、QAチームは他の製品の配送をサポートするためにさらに2か月間予約されています。さらに、設計仕様がないので、QAチームは何をテストする必要があるのか​​まったくわかりません。つまり、独自のコードをテストする資格がないというだけの理由で、実際のテストではない、独自のスモークテストで記述した内容を提供することになります。ここでの最大の要因は、クライアントが約束された機能のいくつかを非常にすばやく確認できることです。プロトタイプがうまくいけば、設計図に戻り、実際のバージョン1.0を設計および計画します-今回は正しく。

単体テストに関する限り、それらは特定の契約を維持するのに適しています(そうしない場合、コードがこれを実行すると約束します-壊れています)。プロトタイピングの場合、契約がそれほど気にならない場合があります。これは、クライアントがなくなったため、またはさまざまなテクノロジー/ツールを使用してバージョン1.0を開発してしまったために、プロトタイプがバージョン1.0になるまで存続できないことが多いためです。ここでの例は、1人の人がPHPに1か月の時間で非常に迅速に作成したクイックプロトタイプWebサイトであり、その後、JEEで書き直すためにチームを編成します。データベースさえ存続しないことがよくあります。この変更。

0
maksimov

ペースの速い小規模な組織では、開発者は生産性を維持し、迅速に行動するようにプレッシャーをかけられているため、自分の変更をテストする必要がないことがよくあります。

変更を加える場合は(バグ修正または機能強化のいずれであっても)、開発者がコードを送信してからさらにQAを行う前に、開発者自身でテストする必要があるとする一般的なポリシーがあります。

私たちの画面はほとんどが画面で変更が加えられた場合、変更が成功したかどうかを確認するために残りのロジックをたどる必要があるように設計されているため、実際にはほとんどのインスタンスに対して単体テストを記述していませんとにかく。

文書化されているかどうかにかかわらず、開発者が独自のテストを行うことが不可欠であると私は思います。なぜなら、ロジックの潜在的な弱点がどこにあるのかを最もよく知っているからです。

つまり、システムの小さな部分ごとに単体テストを作成しなくても、常識テストは関係なく行われるはずです。

0
raffi

欠陥のないアプリケーションのロジックを維持または拡張または伝達するために必要な論理的理解が、チームの最も知識の少ないメンバーがその理解を満たす能力を超える(または将来的には超える可能性がある)場合は、単体テストを作成する必要があります。

基本的には、一度にどれだけ頭に留めておけるかによります。ある程度の複雑さに達するまでは、自分で(変更の影響を完全に理解して)コーディングできるという自信が持てるでしょう。その時点まで、単体テストは注意散漫で邪魔になり、あなたを遅くします。チームでは、しきい値がはるかに低くなるため、グループの愚かさを打ち消すためにすぐに単体テストが必要になります。他の人からテストレスプロジェクトを選んだ場合(または以前のプロジェクトを忘れた場合)、理解がゼロになるため、何か変更する前に単体テストを作成する必要があります。

注:より少ないコードを記述し、YAGNIを実践することで、複雑さ、したがって必要な単体テストの数が抑えられます。

0
Benedict

単体テストは素晴らしいですが、「可動部品」がたくさんある複雑なシステムでは、実際にはあまりテストされません。

ご存知のように、ユニットテストでは、ユニットの入力Xが指定されている場合、出力Yが得られます。Xはすべて適切な入力で、Yはすべて適切な出力です。しかし、ほとんどのコードは、開発者が考えるべきことを実行しますが、実際に実行する必要はありません。
(あなたはそれを銃のように考えるかもしれません。銃には、個別に製造されてから組み立てられた一連の精密部品があります。実際に発砲したときに爆発した場合、特定の各部品が機能について十分にテストされているかどうかは問題ではありません。免責事項:私は火器について何も知りません(:)

この場合、モデルの実稼働環境で実際のシステムテストが必要です。とにかくここで機能がテストされるため、単体テストの価値はわずかに低下します。

ただし、単体テストは、変更を加えたくない機能が実際に変更されていないことを保証するため、この場合でも価値があります。これは、システムの領域で集中的なテストが必要なことを確信できるため、非常に価値があります。

0
user606723

IMOユニットテストは、ユニットテストを導入するために何時間ものリファクタリングや完全な書き換えさえも必要とするコードベースでは不適切です(不要ではありません!)。 。

0
Wayne Molina