web-dev-qa-db-ja.com

あなたのユニットテストコードが「におい」している場合、それは本当に重要ですか?

通常、私はコピーアンドペーストやその他のあらゆる悪い習慣を使用して、単体テストを一緒に投げます。単体テストは通常​​、見苦しくなり、「コードのにおい」でいっぱいになりますが、これは本当に重要ですか? 「本当の」コードが「良い」ものである限り、私はいつも自分に言い聞かせます。さらに、単体テストでは通常、スタブ機能のようなさまざまな「臭いハック」が必要です。

不十分に設計された(「悪臭のする」)単体テストをどの程度心配すべきですか?

52
Buttons840

単体テストの匂いは重要ですか?はい、間違いなく。ただし、ユニットテストは目的が異なり、設計に通知する一連のテンションが異なるため、コードの匂いとは異なります。コードの多くのにおいはテストに当てはまりません。私のTDDの考え方を考えると、ユニットテストの匂いはコードの匂いよりももっと重要であると私は実際に主張します。

ここにいくつかの一般的なユニットテストの匂いがあります:

  • 脆弱性:一見些細な、または無関係なコード変更であっても、テストが頻繁に予期せず失敗しますか?
  • State Leak:テストは、たとえば、実行される順序によって異なる方法で失敗しますか?
  • セットアップ/ティアダウンブロート:セットアップ/ティアダウンブロックが長く、長くなっていますか?彼らは何らかのビジネスロジックを実行しますか?
  • Slow Runtime:テストの実行に長い時間がかかりますか?個々の単体テストの実行に1/10秒以上かかるものはありますか? (はい、私は真剣です、10分の1秒。)
  • 摩擦:既存のテストは新しいテストの作成を難しくしていますか?リファクタリング中にテストの失敗にしばしば悩まされていますか?

匂いの重要性は、匂いがデザインやその他の根本的な問題、つまり「煙があるところ、火があるところ」の有用な指標であることです。テスト臭を探すだけでなく、根本的な原因も探します。

一方、単体テストの優れたプラクティスは次のとおりです。

  • 高速で集中的なフィードバック:テストでは、障害をすばやく切り分け、その原因に関する有用な情報を提供する必要があります。
  • テストコード距離の最小化:テストとそれを実装するコードの間には、明確で短いパスが必要です。距離が長いと、不必要に長いフィードバックループが作成されます。
  • 一度に1つのことをテストする:単体テストでは、1つのことだけをテストする必要があります。別のものをテストする必要がある場合は、別のテストを作成します。
  • バグは、あなたが書くのを忘れたテストです:この失敗から、将来、より優れたより完全なテストを書くために何を学ぶことができますか?
75
Rein Henrichs

心配します。単体テストを作成して、コードが期待どおりに動作することを証明します。自信を持ってすばやくリファクタリングできます。テストが壊れやすく、理解が難しい場合、または維持するのが困難な場合は、失敗したテストを無視するか、コードベースの進化に伴ってテストをオフにして、そもそもテストを書くことの多くの利点を無効にします。

67
jayraynet

数日前 The Art of Unit Testing を読み終えたところです。著者は、本番用コードを実行するときと同じように、単体テストに注意を払うことを推奨しています。

私は不十分に書かれた、保守不可能なテストを直接体験しました。自分で書いたものもあります。テストがお尻を維持するのが面倒なら、それが維持されないことは事実上保証されています。テストがテスト対象のコードと同期しなくなると、それらは嘘と偽りの巣になっています。単体テストの要点は、私たちが何も壊していない(つまり、信頼を生み出す)ことを確信させることです。テストが信頼できない場合、それらは役に立たないよりも悪いです。

19
Joshua Smith

単体テストが実際にコードを「ほとんどの」ケースでテストする限り。 (考えられるすべての結果を見つけるのが難しい場合があるため、意図的に最も言った)。 「臭い」コードは個人的な好みだと思います。私は常に、ジャンクを掘り下げて何が何であるかを理解しようとするのではなく、コードを読んで数秒で理解できる方法でコードを作成します。特にあなたがかなりの時間の後にそれに戻ってきたとき。

結論-そのテスト、それは簡単だと思います。 「臭い」コードと混同したくはありません。

7
Luke

間違いなく。一部の人々は、「どんなテストもまったくテストよりも優れている」と言います。私は強く同意しません-間違って書かれたテストは開発時間を圧迫し、そもそも「壊れた」テストを修正するのに何日も無駄になってしまいます。現在のところ、テストを負担ではなく価値あるものにするために焦点を当てている2つの点は次のとおりです。

保守性

メソッド(howではなく、結果(whatが発生する)をテストする必要があります-)起こります)。テストのセットアップは、実装から可能な限り切り離す必要があります。絶対に必要なサービス呼び出しなどの結果のみをセットアップしてください。

  • モックフレームワークを使用して、テストが外部のものに依存しないようにします。
  • 可能な限り、モックよりもスタブを優先する(フレームワークでスタブを区別する場合)
  • テストにロジックはありません! ifs、switchs、for-eachs、cases、try-catchesなどはすべて、テストコード自体にバグをもたらす可能性があるため、大きな問題です。

読みやすさ

テストでもう少し繰り返しを許可してもかまいません。テストを読みやすくするためには、通常、本番コードでは許可しません。これと上記の保守性とのバランスを取ってください。テストの内容を明確にしてください。

  • テストの「配置、実行、表明」スタイルを維持するようにしてください。これにより、シナリオのセットアップと期待が、実行されるアクションとアサートされる結果から分離されます。
  • テストごとに1つの論理アサーションを維持します(テストの名前に「and」が含まれている場合、複数のテストに分割する必要がある場合があります)

結論として、あなたは「臭い」テストに非常に関心を持つべきです-それらは結局あなたの時間の浪費に終わり、価値を提供することができません。

あなたは言った:

単体テストは通常​​、スタブ機能のようなさまざまな「臭いハック」を必要とします。

Mockingフレームワークを使用するなど、いくつかの単体テスト手法を読むことで間違いなくあなたの生活をずっと簡単にすることができるように思えます。私は非常に強くお勧めします ユニットテストの芸術 、これは上記とはるかにカバーしています。長い間、不十分に記述された、保守不可能な「悪臭のする」テストに苦労した後、私はそれが啓発的であることに気付きました。これは、私が今年行った中で最高の時間の投資の1つです。

6
mjhilton

2つの質問:

  • あなたがあなたが何をテストしているのか絶対に肯定的ですか考えるあなたがテストしている?
  • 他の誰かがユニットテストを見ると、彼らはコードが何であるかを理解することができますすることを想定

ユニットテストで繰り返し行われるタスクを処理する方法は、最も一般的にはセットアップコードとティアダウンコードです。基本的に、テストセットアップメソッドとテストティアダウンメソッドがあり、すべての単体テストフレームワークがこれをサポートしています。

単体テストは小さく、簡単に理解できる必要があります。そうでない場合、テストが失敗すると、かなり短い期間で問題をどのように修正しますか。コードに戻る必要がある場合は、今後数か月間は自分で簡単にできるようにします。

5
Berin Loritsch

ゴミの臭いがし始めたら、それを取り出す時です。テストコードは、製品コードと同じくらいクリーンでなければなりません。お母さんに見せてくれませんか?

5
Bill Leeper

これを正当な質問として扱う方法さえ理解するのにしばらく時間がかかったので、私はほとんど答えを提出しませんでした。

プログラマーが「ベストプラクティス」に携わる理由は、美的理由や、「完璧な」コードを望んでいるためではありません。それは彼らが時間を節約するからです。

  • 良いコードは読みやすく理解しやすいので、時間を節約できます。
  • バグを修正する必要がある場合、より簡単かつ迅速にバグを見つけることができるため、時間を節約できます。
  • コードを拡張したい場合は、拡張が簡単かつ高速であるため、時間を節約できます。

それで、あなたの質問(私の観点から)は、自分の時間を節約するか、私の時間を無駄にするコードを書くべきですか?

その質問に対して私は言うことができます、あなたの時間はどのくらい重要ですか?

参考までに:スタブ、モック、およびモンキーパッチはすべて正当な用途があります。それらは、その使用が適切でない場合にのみ「におい」を発します。

3
dietbuddha

ここに他の答えに加えて。

単体テストの質の低いコードは、単体テストスイートに限定されません。

単体テストで満たされる役割の1つはドキュメントです。

ユニットテストスイートは、APIがどのように使用されることが意図されているかを確認するための場所の1つです。

APIの呼び出し元がユニットテストスイートの一部をコピーする可能性は低くないため、不正なテストスイートコードが他の場所のライブコードに感染します。

3
Paul Butcher

私は特に、ユニットテストを堅牢にしすぎないようにしています。堅牢であることを理由にエラー処理を開始する単体テストを見てきました。最終的には、キャッチしようとしているバグを飲み込むテストになります。ユニットテストはまた、物事を機能させるためにかなり頻繁にファンキーなことをしなければなりません。リフレクションを使用してプライベートアクセサーの全体的なアイデアについて考えてみてください...実稼働のコードでそれらのすべてを見た場合、私は10回のうち9回心配します。何がテストされているかを考えるためにより多くの時間を費やす必要があると思いますコードの清潔さよりも。大規模なリファクタリングを行う場合は、テストをかなり頻繁に変更する必要があるので、それらを一緒にハックし、所有権の感触を少し減らし、時が来たらそれらを書き直したり再作業したりする動機を高めてみませんか?

2

重度の低レベルのカバレッジを行う場合、深刻な変更を行う場合、製品コードと同じくらい多くの時間をテストコードに費やすことになります。

テスト設定の複雑さに応じて、コードはさらに複雑になる場合があります。 (たとえば、httpcontext.currentと、偽のモンスターを正確に構築しようとする恐ろしいモンスターの例)

製品が既存のインターフェイスに重大な変更を加えることがほとんどなく、ユニットレベルの入力の設定が非常に簡単なものでない限り、実際の製品としてのテストの理解について心配する必要があります。

2
Bill

コードのにおいは、コードの問題であり、後で変更または理解する必要があります。

そのため、特定の単体テストに「近づく」必要がある場合は、コードの臭いを修正する必要がありますが、以前は修正しないでください。

0
Ian