2

2 つの数値を渡して最大の数値を返すメソッドを開発しているとしましょう。私はこの TDD スタイルを行っているため、多数の単体テストを行い、次の実装を考え出します。

public int GetHighestNumber(int x, int y)
{
    if (x > y) return x;
    else return y;
}

これは非常にうまく機能します。

テストは、実装を作成するために使用されています。実装が完了したら、これらの単体テストを保持する意味は何ですか? 家がすでに引き渡された後、家の周りに足場を置いておくようなものです。

単体テストを行う理由や、TDD を使用するかどうか/いつ使用するかについては調べていません。これらのテストを一時的な手段として保持し、開発者をサポートする必要がない場合は削除するのではなく、コードが完全に実装された後も単体テストを保持する必要がある理由に興味があります。


編集

CodeGnomeについてコメントした後、これは主に開発者を正しい方向に向けるために作成された TDD テストに関するものであることを強調する必要があることに気付きました。いわば足場。

しかし、すべてのコメントに感謝します。


すべてのメッセージを読んだ後、次の 2 つのことを結論付けることができます。

  1. スタックオーバーフローの誰も実際に元の質問を読んでいません
  2. テスト自体が役に立たないからではなく、おそらく非常に無能な同僚と一緒に作業していて、これらのテストは彼らが信じられないほど愚かなことをするのを防ぐためにあるからです。
4

8 に答える 8

9

実際のコードが「完成」することはほとんどありません。

要件は変化し、拡大します。機能が追加されます。TDD にもかかわらず、修正すべきバグがあります。

単体テストは回帰テストとしても機能し、これらの変更後もコードが機能することを証明します。実際、これは単体テストの最も価値のある側面です (設計上の利点が自分自身を欺いていることはそれほど重要ではないと主張する TDD 支持者は誰でも)。

于 2012-08-03T09:06:21.963 に答える
5

いくつかの理由が (少なくとも) 思い浮かびます。

  • コードが想定されている/想定されていないことを文書化するのに役立ちます
  • 当然のことながら、将来の開発者にメソッドの使用例を提供します
  • 後の段階でメソッドを変更する場合、これらは回帰テストとして機能します。変更後も元のテストが引き続きパスすること、および何も壊れていないことを確認できます。

編集

「そのメソッドに変更が加えられることはなく、そのレベルでの回帰テストは不要です」

賢い人が到着してコードを次のように変更するまで

if (x - y > 0) return x;
else return y;

(はい、その方法でなくても、他の場所で発生する可能性があります)。

うまくいけば、テストの 1 つが次のようになります。

assertEquals(Integer.MAX_VALUE, GetHighestNumber(Integer.MIN_VALUE, Integer.MAX_VALUE));

そして、そのテストは失敗します。

于 2012-08-03T09:06:47.223 に答える
3

テストによる回帰の防止

適切に実装された単体テストは、プログラムの動作を検証します。「レガシー」テストは、プログラムを拡張または変更するときに、誤って新しいバグを導入したり、コードに回帰を作成したりしないようにします。

コードが進化するにつれて、テストが明確な目的を果たさなくなった場合、テストは確実にコードとともにリファクタリングできます。ただし、最初からテストする価値のある機能がある場合は、コードのライフサイクル全体でその動作をテストし続けることが引き続き有効です。

単体テストに多くの「役に立たない」テストが含まれていることがわかった場合は、間違ったもの (動作ではなく構成など) をテストしている可能性があります。または、単にテストをリファクタリングして、時間の経過とともにテストが古くなるのを防ぐ必要があるかもしれません。これらはサニティ チェックであり、従来の足場ではありません。

于 2012-08-03T09:11:30.430 に答える
1

回帰、回帰、百万回の回帰。

機能が実装された後にテストがないという架空の状況を想像してください。

  1. アプリケーションに月次レポート機能を実装します。例として、データベースからエンティティを取得し、その定義をスキャンして適切なテーブルを作成するとします。
  2. レポート機能をリリースすると、クライアントはすべてが機能し、希望どおりの素敵な光沢のあるテーブルが作成されたことに満足しています。
  3. しばらくして、あなたの友人はデータ アクセス レイヤーに関する内部作業を行います。データベースを最適化するために、いくつかのエンティティ定義を変更します。
  4. これを重要なパッチとしてリリースします。クライアントは再び満足しています。アプリケーションの動作が大幅に速くなったようです。
  5. 数日後、いらいらしたクライアントから、レポートがゴミを生成していると主張する電話を受けました。

誰のせい?もちろん、あなた。どうしたの?コードが機能しなくなりました。たぶん、まったく機能しませんでしたか?たぶん、1つの特別なケースで機能しましたか?このばかげた質問はさておき、実際に何が起こったのかは誰もが知っています。エンティティ コードで行われた変更により、レポート生成機能が壊れました。あなたの友人が問題を引き起こした、あなたはその責任を負います。

これが、テストを自動化した理由です(ユニットだけでなく)。回帰を防ぐため。リグレッションが原因のバグを手動で見つけるのは非常に困難です。それらは、変更直後、しばらくしてから、別の変更の後で表示される場合があります。あなたは、決して知らない。ここで、単体テストが (他のテスト方法と共に) 役立ちます。上記の仮説的な状況から、あなたの友人は、テストを実行していれば、レポート ジェネレーターのコードを壊したことを知っていたでしょう。そのような単純な。

このプログラマーのSEの質問からのいくつかのポイントコメント:

大学は、単体テストを純粋な信念から実行しなければならないものとして公開し、予防および制御する必要のある病気があり、その病気が回帰と呼ばれることを詳細に説明しません。

単体テストは、コードに欠陥がないことを証明するものではありませんが、コードが設計どおりに動作し、今日の動作を明日も実行し続けるという自信を高めます (またはそうする必要があります)。

これらすべてのテストが本当に必要かどうか疑問に思うときはいつでも、心に留めておくべきことがあります。

于 2012-08-03T09:49:07.523 に答える
0

テストは、モジュールのドキュメントとしてチームに役立つはずです。それらは、入口値と予想される出口値の読者の例を示しています。彼らは次の人にルーチンを呼び出す方法を明確に指示する必要があります。

上記の多くのコメントで、次のプログラマーについて多くのことを想定していることに気づきました。彼は賢くて有能であり、コードを注意深く読み、メソッド名を信頼します。それらの仮定をすることは危険です。今日は上司の下ではないかもしれませんが、ある時点で、現在の仮定が示すよりも能力の低い誰かによってコードが保守される可能性があります。

このように考えてください。コードがオープンソースになり、さまざまなレベルの能力を持つ何百人もの人々が突然それを見ている場合、彼ら全員がそれを理解しますか?おそらくそうではありません。

モジュールの作成者にとって明らかなことは、他の人にとってはそれほど明白ではないことがよくあります。

于 2012-08-05T00:28:22.480 に答える
0

TDDロック。適切な TDD は設計を容易にします。したがって、失敗しないテストは、コードが記述された後はほとんど、またはまったく価値がありません。ただし、それらの存在は、リファクタリングを促進するための安全ベルトのような感覚を提供します。ただし、コードがオープン/クローズの原則に従っている場合、コードが記述されると、テストはそれ以上役に立たないと見なされる場合があります。

私が従うルールは、元の設計が保持され、要件のマイナーな変更を実装している場合 (たとえば、小文字のプレフィックスを持つ文字列を構築する)、テストが役立ち、回帰を回避することです。ただし、クラスの設計または意図が単に間違っていることに気付いた場合、単体テストは変更の阻害要因になる可能性があります (変更はリファクタリングとは異なります)。

難しいのは、要件の変化による意図の変化を認識することです。

いつものように、白黒の答えはありません。

于 2012-08-03T09:15:25.943 に答える
0

TDD の関連性が高いほど、プロジェクトをより大きくスケーリングする必要があります。

大規模で複雑なプロジェクトに取り組む場合、すべてのレベルのコード部分間に多くの依存関係があります。自動化されたテストにより、あるポイントのバグ修正が他の部分の新しいバグの発見にすぐにつながる可能性があります。

このような大きなプロジェクトで経験を積むとすぐに、それがどれほど価値があるかがわかります。

于 2012-08-03T09:49:36.017 に答える
0

上記のコードを使用すると、次のテストが実行されます。

  • X が Y より大きい場合、X が返されます。
  • Y が X より大きい場合、Y が返されます。
  • X が Y に等しい場合、Y が返されます。

そのため、そのメソッドの予想される動作を文書化し、それを適用する 3 つの短時間で迅速に実行されるテストを行います。(両方ともそれらを保持する非常に正当な理由です)。

上記の 3 つのテストよりもはるかに多くのテストがある場合は、テストの数を減らし始めることができます。すべてのコードと同様に、不要な場合はリファクタリングして削除する必要がありますが、不要なものだけを削除していることを確認してください。

于 2012-08-03T10:01:15.977 に答える