web-dev-qa-db-ja.com

単体テストのコードの品質?

単体テストを作成するとき、コードの品質と可読性を高めるために余分な時間を費やす価値はありますか?

テストを書くとき、私はしばしば デメテルの法則 を壊します。これは、より速く書くため、そして多くの変数の使用を避けるためです。技術的には、単体テストは直接再利用されません。コードに厳密にバインドされているため、テストに多くの時間を費やす理由はありません。機能する必要があるだけです。

23
m3th0dman

品質と読みやすさの点で、本番用コードよりも単体テストの方が優れているかどうかにかかわらず、同じことを間違いなく行う必要があります。多くの場合、ユニットテストはコードの一部を理解しようとするときに最初に目にするものであり、読者はテストを見て何が問題になっているのかをすばやく理解する必要があります。単体テストはまた、大幅に変更される傾向があり、それらの設計が堅牢でない場合、多くの場合、テストの利点を無効にします。

デメテルの法則の違反は、その理由のためのユニットテストで間違いなく問題であり、私の心から浮かび上がる2つの問題もあります。

  • テストでデメテルの法則が ArrangeまたはAct セクションで違反している場合、ユニットテストはコードの別のコンシューマーであり、おそらく呼び出して動作するため、これはおそらく本番用コードでも同様の兆候です。他の製品コードと同じ方法でテスト中のクラス。

  • テストのアサートセクションでデメテルの法則に違反する場合(つまり、テスト対象のオブジェクトの依存関係グラフに深くネストされているものの値を確認する場合)、それらはユニットテストではなく実際に統合テストである可能性があります。言い換えると、TestAでABCDが何かと等しいと主張する場合、実際にはAではなくDとAをテストしようとしている可能性があります。 。

ちなみに

デメテルの法則を頻繁に破るのは、記述を高速化し、あまり多くの変数を使用しないためです。

あなたはそのことを認識する必要があります

var grab = myDependency.Grab;
var something = grab.Something;
var very = something.Very;

very.Deep();

実際、デメテルは

myDependency.Grab.Something.Very.Deep();

それがあなたの意図したことなら.

11
guillaume31

単体テスト用の高品質のコードを書くことに時間を費やす価値は絶対にあります。

  • 他のコードと同様にメンテナンスが必要になります。
  • ユニットテストは、システムのドキュメンテーションの最良のソースの1つであり、間違いなく最も信頼できる形式です。彼らは本当に示す必要があります:
    • 意図:「予想される動作は何か」。
    • 使用法:「このAPIの使用方法は?」.
  • 他のコードと同様にデバッグが必要です。

ややアドホックなアプローチを採用する1つの要因は、ユニットテストがパブリックAPIになることはないため、どのインターフェイスなどについて心配する必要がないことです。あなたが公開しています。

47
vaughandroid

はい、それは重要です。単体テストを他のコードと同等の標準に保つ必要がある理由はいくつかあります。

  • 各単体テストは、受験者のドキュメントとしても機能します。テストが包括的で、可能な限り多くのEdgeケースとエラー条件をカバーする場合、それらは多くの場合、クラスまたは関数のコメント文書を置き換えることができます。また、コードベースを初めて使用するユーザーの出発点にもなります。

  • 単体テストもバグが多い場合があります。また、コードが適切に記述されていると、エラーがより見やすくなります。

  • 何らかの理由で、後でモジュールを分割する必要がある場合は、おそらくユニットテストも分割する必要があります。テストが容易に識別できる依存関係を持つようにテストが記述されている場合、これは簡単です。

そうは言っても、実用性の問題は常にあります。コードの言語と性質によっては、テスト対象のコードよりもテストに多くの時間を費やすことなく「クリーン」な単体テストを作成するのが難しい場合があります。その場合、私は通常、完全なカバレッジをあまり気にせずに、簡単で迅速なものと最も重要な機能のテストにフォールバックします。バグが後から発生するときはいつでも、バグのテストを作成し、新しいテストと既存のテストをリファクタリングしてそれらをより良くできるかどうかを確認します。

22

単体テストを読み取ることができず、次に失敗したときに何がテストされているかがわからない場合は、デバッグ時間を2倍に費やします(テストの内容を確認し、テストしているコードを修正するために一度)。

正直なところ、ユニットテストは期待される結果をもたらすはずです。手順を実行します。実際の結果を得る;書きやすく理解しやすい実際のタイプの構造に対して期待されるテスト

12
ratchet freak

最も重要な実用的な理由は、コードを変更するたびに単体テストを変更することです。また、TDDを実行している場合は、最初に単体テストを変更することもできます。

テストで次のいずれかを実行します。

  • 重複したコード
  • 読みやすさの低下
  • 密結合
  • 時間的カップリング
  • 高い循環的複雑度(多数の依存関係)

そして、変更が必要になったとき、あなたは多くの仕事に携わっています。

あなたが提案したようにあなたのテストを扱う、そしてあなたはそれを後悔することになります。 「TDDが機能しない」という誤った結論に達する可能性もあります。

1
Yam Marcovic

テストコードは、プロダクションコードと同じくらいの愛を受け取る必要があります。読みやすくするために、多分もっと。あなた以外の誰か(コードを離れてから2週間後も含む)が何が起こっているのかを理解していると思われる場合は、コードをすっきりさせてください。

これの意味は:

  • テストデータの構築をビルダークラスに抽出します。
  • 複数のアサーションを個別のアサーションメソッドに抽出します。
  • 名前は正確に入力してください。 Assert.That(x4, Is.EqualTo(y16*2*SOME_VALUE), ASS_ERR_TXT_56)は、ほとんどの読者にとってほとんど意味がありません。

極端に言えば、テストは文章と同じくらい読みやすく、理解しやすいように書くことができます。極端なテスターはおそらく、10行を超えるユニットテストは悪いテストだと言うでしょう。

1
Morten

これらの単体テストが「一時的」であるかどうかによって異なります。もし

  1. テストは頻繁に使用されます。

  2. 開発者は、他の開発者が作成した単体テストを使用する必要があります。

  3. ほとんどのテストは単体テストによって行われます

次に、テストを適切に記述する必要があります。テスト自体にバグがある場合、特にテストが作成されてから時間が経過している場合は、バグを見つけて修正することは困難です。

一方、これらのテストが開発者自身のみによって使用されている場合は、問題ないと思います。しかし、それでも「読み取り可能な」コードを書く方が望ましいです。ラチェットフリークが言ったように、テストを適切に作成するよりもテストの修正に多くの時間を費やす必要があります。

0
superM