ユニットテストは後でコメントアウトされる傾向があるため、または統合テストはより価値があるため、ユニットテストを作成しないのは合理的ですか?


35

私は同僚とユニット/統合テストについて話し合っていましたが、彼はユニットテストの作成に対して興味深いケースを作りました。私は大規模なユニットテスト(主にJUnit)の支持者ですが、彼がいくつかの興味深い点を指摘したので、他の人の意見を聞くことに興味があります。

彼のポイントを要約するには:

  • 主要なコードの変更(POJOの新しいセット、主要なアプリケーションのリファクタリングなど)が発生した場合、単体テストは修正されるのではなくコメントアウトされる傾向があります。
  • ユースケースをカバーする統合テストにより多くの時間を費やすことができます。これにより、より小さなスコープのテストの重要性が低くなります。

これについての考え?統合テストは少なくとも同じくらい価値があるように聞こえますが、私はまだプロユニットテストです(一貫して改善されたコードを生成しているのを見ています)。


9
あなたはそれを自分で言いました:ユニットテストを書くことは、テスト可能なコードを書くことを強制するので、より良いコードを生成します。単体テスト可能なコードには、全体的な品質を向上させる非常に重要なプロパティが多数あります。
ロバートハーベイ

1
@Robert Harvey-同意-これらのプロパティのリストを参照してください。
ジェフレヴァイン

18
最初の点については、基本的にユニットテストの欠点は、使用しないと機能しないことです。他の練習についても同じことが言えます。また、パッシブボイスの使用は、ユニットテストで誰かが積極的にコメントを外しているという事実を明らかにしています。したがって、チームの開発者から賛同を得ていないようですが、これは別の問題です。
ジャックB


回答:


62

私はあなたの友人を味方にする傾向があります。なぜなら、ユニットテストは頻繁に間違ったことをテストしているからです。

単体テストは本質的に悪くはありません。ただし、入力/出力フローではなく、実装の詳細をテストすることがよくあります。これが発生すると、完全に無意味なテストになります。私自身のルールは、優れた単体テストは、あなたが何かを壊しただけだということです。不正な単体テストは、単に何かを変更したことを伝えるだけです。

私の頭の上の例は、数年前にWordPressに組み込まれた1つのテストです。テストされている機能は、互いに呼び出されるフィルターを中心に展開され、テストでは、コールバックが正しい順序で呼び出されることを確認していました。ただし、(a)チェーンを実行してコールバックが予想される順序で呼び出されることを確認する代わりに、テストは(b)おそらく公開されるべきではない内部状態を読み取ることに焦点を当てました。内部構造を変更すると、(b)赤に変わります。一方、(a)内部に変更を加えると予想される結果が損なわれる場合にのみ赤に変わります。(b)私の見解では、明らかに無意味なテストでした。

いくつかのメソッドを外部に公開するクラスがある場合、私のビューでテストする正しいものは後者のメソッドのみです。内部ロジックも同様にテストすると、複雑なテスト方法を使用したり、何かを変更するたびに常に壊れる単体テストを使用して、内部ロジックを外部に公開することになります。

とは言っても、あなたの友人があなたが提案しているように単体テスト自体について批判的であるならば、私は驚くでしょう。むしろ私は彼が実用的だと思うでしょう。つまり、書かれた単体テストは実際にはほとんど無意味であることに気づきました。引用:「単体テストは、書き直されるよりもコメントアウトされる傾向があります」。私には暗黙のメッセージがそこにあります-彼らがそれをやり直す必要がある傾向があるなら、彼らは吸う傾向があるからです。その場合、2番目の命題は次のとおりです。開発者は、間違えにくいコード、つまり統合テストの作成に費やす時間を節約できます。

そのようなものとして、それは良いものでも悪いものでもありません。間違いを犯すのはずっと簡単で、実際には実際には非常に頻繁に間違っているというだけです。


13
これ、これ、百倍。これは、テスト駆動開発の素晴らしいところです。最初にテストを書くと、実装の詳細をテストするのではなく、実装しようとしていた意図した動作をテストするテストを書くのに役立ちます。
ウィルベル

9
脆弱な単体テストは単体テストの固有の特性ではなく、単体テストの目的を誤解しているとは思いません。ここで必要なのは、開発者のためのより良い教育です。実装の詳細を単体テストする場合、間違っています。「テストするために」プライベートメソッドをパブリックにすると、間違っていることになります。常にパブリックインターフェイスと動作をテストしてください。実装の詳細よりも頻繁に変更されることはありません。
アンドレスF.

2
@DocBrown:そうではありません。私が意図したことは、OPの同僚がほとんどの場合-または少なくともすべての場合で単体テストに夢中になった会社で遭遇したことがあるほど間違っていることです。
デニスドベルナルディ

3
@DenisdeBernardy:私のポイントは、あなたが書いたものはすべて実践からの多くの知恵で確かに正しいですが、「統合テストとしての統合テストより良い代替案」。
Doc Brown

5
私はDoc Brownに強く同意します。基本的に、あなたの立場はユニットテストが良いということのようですが、それらが間違って書かれていると、それらは面倒になります。したがって、あなたはOPの同僚にまったく同意せず、それらの有用性を主張する前に実際にユニットテストを書くことを確認する必要があるだけです。最初の文は、OPの同僚がそうでないように思えても同意することを述べているので、あなたの答えは非常に混乱していると思います。それは、一般的に単体テストに対するケースではなく、不適切に書かれた単体テストについての暴言のようです(実際問題です、私は認めます)。
ビンセントサバード

38

主要なコードの変更が発生すると、単体テストは修正されるよりもコメントアウトされる傾向があります。

もちろん、既存のすべてのテストをコメントアウトすると、すべてのテストが「グリーン」になったと考える、規律のない多くのカウボーイコーダーがいます。ユニットテストのリワークは、最初にそれらを書くのと同じ量の規律を必要とするので、ここで取り組む必要があるのは、チームの「完了した定義」です。

小規模スコープのテストの重要性を低く/小さくするユースケースをカバーする統合テストに時間を費やす方がよい。

それは完全に間違っているわけでも完全に正しいわけでもありません。有用な統合テストを作成するための労力は、作成するソフトウェアの種類に大きく依存します。統合テストを単体テストとほぼ同じくらい簡単に作成できるソフトウェアをお持ちの場合、それらはまだ高速で実行され、コードを適切にカバーできるので、同僚はポイントを持っています。しかし、多くのシステムでは、これらの3つのポイントを統合テストで簡単に満たすことはできません。そのため、ユニットテストも実行する必要があります。


これは私たちがそれを議論していたとき、私が感じたものです。ユースケースのために完全で関連する統合テストを作成できると仮定すると、単体テストが重要なポイントになるようです。(今はこれを書いていますが、バックエンドが別のアプリケーションのWebサービスに変換されるなど、予期しない将来のケースを考えています)。
ジェフレヴァイン

+1「完了の定義に取り組む必要がある」ため。よく言った!
アンドレスF.

14

私はあなたの同僚の議論を受け入れることを知りません。

  1. ユニットテストがコメントアウトされている場合、それは誰かが怠けているからです。それはユニットテストのせいではありません。そして、あなたが言い訳として怠zyを使い始めたなら、あなたは少しの努力を必要とするほとんどすべての慣習に反対することができます。
  2. 正しく実行すれば、単体テストに長い時間をかける必要はありません。彼らはあなたがより重要な仕事をすることを止めていません。壊れたコードの修正が他の何よりも重要であることに全員が同意する場合、単体テストは非常に重要です。投稿条件をテストする簡単な方法です。それがないと、事後条件の保証を満たしていることをどのようにして知ることができますか?そして、もしそうでなければ、あなたのコードは壊れています。

単体テストに対する他の、より説得力のある議論があります。まあ、彼らに対して正確ではありません。DHHのテストによる設計損傷から始めます。彼は楽しい作家なので、読んでください。私がそれから取ったもの:

ユニットテストに対応するために大きな設計変更を行うと、プロジェクトの他の目標を妨げる可能性があります。可能であれば、どちらのアプローチを採用するのが簡単かを公平な人物に尋ねてください。高度にテスト可能なコードを理解するのが難しい場合、単体テストから得たすべての利点を失う可能性があります。抽象化が多すぎることによる認知のオーバーヘッドにより、速度が低下し、漏れやすい間違いが簡単になります。割引しないでください。

微妙で哲学的になりたいなら、多くの素晴らしいリソースがあります:


その記事の1、私たちはhere-書くことができるもの全てよりのOPケースに良い答えかもしれない
ドク・ブラウン

怠inessが言い訳であることについてのポイント番号1に対して+1。私はそれがどれほどイライラするかを十分に強調することはできません。私はそこに行ったことがある。最近、実際に。
グレッグブルクハート

3
理由1は単体テストの誤りではありませんが、それでも単体テストに対する理由です。
user253751

DHHの記事を読んだ後、彼がKent BeckとMartin Fowler(YouTubeにいます)とトピックについて議論したビデオを必ず確認してください。彼はこれらの議論でかなり洗練しています。
ジュール

6

主要なコードの変更(POJOの新しいセット、主要なアプリケーションのリファクタリングなど)が発生した場合、単体テストは修正されるのではなくコメントアウトされる傾向があります。

それをしないでください。もしそれをする人を見つけたら、彼らを殺し、彼らの子供がその欠陥遺伝子を遺伝するかもしれないので、彼らが繁殖しないことを確かめてください。CSIのテレビ番組を見るとわかるように、キーとなるのは、多くの誤解を招くDNAサンプルをいたるところにばらまくことです。このように、犯罪現場を非常に多くのノイズで汚染するため、DNAテストの費用と時間がかかる性質を考えると、犯罪者があなたにそれを突き止める確率は天文学的に低くなります。


4

単体テストは、手直しではなくコメントアウトされる傾向があります。

その時点で、コードレビュープロセスは「単体テストを修正します」と表示しますが、これはもう問題ではありません。


3

主要なコードの変更(POJOの新しいセット、主要なアプリケーションのリファクタリングなど)が発生した場合、単体テストは修正されるのではなくコメントアウトされる傾向があります。

私は常にリファクタリングと機能の変更を別々にしようとしています。両方を行う必要がある場合、通常は最初にリファクタリングをコミットします。

機能を変更せずにコードをリファクタリングする場合、既存の単体テストは、リファクタリングが機能を誤って壊さないことを保証するのに役立つと考えられています。そのため、このようなコミットでは、単体テストを無効にするか削除することを重要な警告サインと見なします。コードをレビューしているときは、開発者にそうしないように指示する必要があります。

機能を変更しない変更でも、ユニットテストの欠陥のためにユニットテストが失敗する可能性があります。変更するコードを理解していれば、そのような単体テストの失敗の原因は通常すぐに明らかになり、修正が容易です。

たとえば、関数が3つの引数を取る場合、関数の最初の2つの引数間の相互作用をカバーする単体テストは、3番目の引数に有効な値を提供することに注意しなかったかもしれません。単体テストのこの欠陥は、テストされたコードのリファクタリングによって明らかになる可能性がありますが、コードが何をすべきか、単体テストが何をテストしているかを理解していれば簡単に修正できます。

既存の機能を変更する場合、通常はいくつかの単体テストも変更する必要があります。この場合、単体テストは、コードが意図したとおりに機能を変更し、意図しない副作用がないことを確認するのに役立ちます。

バグを修正したり、新しい機能を追加する場合、通常は単体テストを追加する必要があります。それらの場合は、最初に単体テストをコミットし、後でバグ修正または新しい機能をコミットすると役立ちます。これにより、新しいユニットテストが古いコードではパスしなかったが、新しいコードではパスしたことを確認しやすくなります。ただし、このアプローチには完全に欠点がないわけではないため、新しい単体テストとコード更新の両方を同時にコミットすることを支持する議論も存在します。

ユースケースをカバーする統合テストにより多くの時間を費やすことができます。これにより、より小さなスコープのテストの重要性が低くなります。

これにはいくつかの真実の要素があります。ソフトウェアスタックの上位層を対象とするテストでソフトウェアスタックの下位層をカバーできる場合、コードをリファクタリングする際にテストがより役立つ場合があります。

ただし、単体テストと統合テストの正確な区別については同意しないと思います。そして、ある開発者が単体テストと呼び、別の開発者が統合テストと呼ぶテストケースがあれば、それが有用なテストケースであることに同意できる限り心配しません。


3

統合テストは、システムが想定どおりに動作するかどうかを確認するために行われ、常にビジネス価値があります。単体テストは常にそうするとは限りません。たとえば、単体テストでは、デッドコードをテストできます。

情報を提供しないテストはすべて無駄であると言うテスト哲学があります。コードの一部が処理されていない場合、そのユニットテストは常に(またはほぼ常に)緑色になり、情報をほとんどまたはまったく提供しません。

すべてのテスト方法は不完全です。あるメトリックで100%のカバレッジを得たとしても、入力データのほぼすべての可能なセットを通過するわけではありません。したがって、単体テストが魔法だとは思わないでください。

ユニットテストを行うことでコードが改善されるという主張をよく目にします。私の意見では、ユニットテストがコードにもたらす改善は、コードに慣れていない人々に、コードを小さく、十分にファクタリングされた部分に分割することを強制することにあります。コードを小さく、よくファクタリングされた部分で普通に設計することに慣れた場合、それを強制するための単体テストが不要になることがあります。

単体テストの規模とプログラムの規模によっては、膨大な量の単体テストが発生する場合があります。その場合、大きな変更は難しくなります。大きな変更が単体テストの多くの失敗を引き起こす場合、変更を拒否するか、多くのテストを修正するために多くの作業を行うか、テストを破棄することができます。どの選択肢も理想的ではありません。

単体テストは、ツールボックス内のツールです。彼らはあなたに奉仕するためにそこにいます。少なくともあなたが入れたのと同じくらいそれらから抜け出すようにしてください。


3

単体テストは、一部の支持者が主張する特効薬ではありません。しかし、一般的に彼らは非常に肯定的な費用/便益比を持っています。彼らはあなたのコードを「より良い」ものにすることはなく、おそらくよりモジュール化するでしょう。「より良い」には、「テスト容易性」が意味するものよりも多くの要因があります。しかし、彼らはあなたが考えたすべての場合と使用法でそれが機能することを保証し、ほとんどのバグ(おそらくもっと些細なもの)を排除します。

ただし、単体テストの最大の利点は、コードの柔軟性と変更に対する回復力を高めることです。機能をリファクタリングまたは追加でき、何も壊していないことを確信できます。これだけでも、ほとんどのプロジェクトで価値があります。

あなたの友人によって作られたポイントを参照する:

  1. POJOを追加するとユニットテストが壊れる場合は、おそらく非常に不適切に記述されています。POJOは通常、ドメインについて話すために使用する言語であり、解決する問題は、明らかにビジネスロジック全体を意味し、おそらくプレゼンテーションコードを変更する必要があります。プログラムのこれらの部分が変更されないことを保証するものは期待できません...

  2. ユニットテストが悪いと不満を言うのは、人々がそれらをコメントアウトするので、シートベルトを着用しないので不満を言うのに似ています。コードのテストをコメントアウトして何かを破った場合、彼は上司と非常に深刻で不快な会話をすることになります...

  3. 統合テストは、単体テストよりもはるかに優れています。質問なし。特に製品をテストしている場合。しかし、単体テストが提供するものと同じ価値、対象範囲、および正確性の保証を提供する、優れた包括的な統合テストを作成することは非常に困難です。


2

私は単体テストに対して1つの議論しか考えられず、それはかなり弱いです。

ユニットテストは、後の段階でコードをリファクタリングまたは変更するときに、その価値の大部分を示します。機能を追加するのに必要な時間が大幅に短縮され、何も破損していないことを確認できます。

ただし、そもそもテストの作成には(わずかな)コストがかかります。

したがって、プロジェクトが十分に短く、継続的なメンテナンス/更新を必要としない場合、テストを書くコストがそれらの利益を上回る可能性があります。


+1された質問に真剣に答えようとしたため。
ラバーダック

2
単体テストのコストは間違いなく小さくありません。通常、優れた単体テストは、テストするよりも書くのに時間がかかります。ほとんどの場合、メリットはコストを上回ります。
AK_

1
理論的にのみ-リファクタリングを行うと、ユニットテストもほとんど常に細かすぎるため、ユニットテストの更新にも膨大なコストがかかります。あなたが良い統合テストスイートを持っていることについて話していたら、あなたは正しいでしょう。
gbjbaanb

プロジェクトが十分に短いですし、継続的なメンテナンス/更新を必要としない場合 -レガシーシステムのほとんどはテストせずに短いプロジェクトとして始まっている-とテストをせずにgrowedシステムを維持するためのより多くの開発者を雇うで終わる
ファビオ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.