私の会社の人々は、単体テストを多くの余分な作業と見なしており、既存の機能テストよりもメリットが少ないと考えています。単体テストと統合テストは価値がありますか? テストを念頭に置いて設計されていない大規模な既存のコードベースに注意してください。
9 に答える
ほとんどの人は、自動化された単体テストが何のためにあるのかを知りません。
- 新しいテクノロジーを試すには
- コードの一部を使用する方法を文書化するには
- 死んだバグが死んだままであることを確認するには
- コードをリファクタリングできるようにするには
- コードの主要部分を変更できるようにするため
- 製品の品質が低下しない可能性のある低い透かしを作成します
- これで、何かが機能することがわかったので、開発速度を上げます(顧客がバグを報告するまで機能することを期待するのではなく)。
したがって、これらの理由のいずれかがメリットをもたらす場合は、自動化された単体テストが適しています。そうでない場合は、時間を無駄にしないでください。
(「機能テスト」とは、システム全体またはアプリケーションが稼働していることを含むテストを意味していると想定しています。)
次の3つの理由から、新しい機能を作成したときに単体テストを行います。
- これにより、コードをより早く処理できるようになります。「単体テストに失敗し、コードを修正し、単体テストに合格」の所要時間は、通常、「機能テストに失敗し、コードを修正し、機能テストに合格」よりもはるかに短くなります。
- コードをよりクリーンな方法で設計するのに役立ちます
- それは私が私のコードとそれを維持するようになったときにそれが何をすることを意味するのかを理解するのに役立ちます。変更を加えると、何も壊れていないという自信がつきます。
(これには、Epagaによって提案されたバグ修正が含まれます。)
Michael Feathersの「レガシーコードを効果的に使用する」を強くお勧めします。これは、そのために設計されていないコードベースの単体テストを開始する方法のヒントを提供します。
機能テストが自動化されているか、手動で実行されているかによって異なります。後者の場合、これらのユニット/統合テストを実行するコストは手動の機能テストを実行するよりもはるかに低いため、あらゆる種類の自動テストスイートが役立ちます。そこで実際のROIを示すことができます。いくつかの統合テストを書くことから始めることをお勧めします。将来、時間/予算が許せば、ユニットテストを見てください。
レガシーコードの単体テストをさかのぼって作成することは、多くの場合、価値がありません。機能テストに固執し、それらを自動化します。
次に、バグ修正(または新機能)には、少なくとも修正をテストする単体テストを伴う必要があるというガイドラインがあります。そうすれば、プロジェクトを少なくとも正しい方向に進めることができます。
そして、私は「レガシーコードで効果的に作業する」ことを推奨する際にJon Skeetに同意する必要があります(どうして私はできませんでしたか?)、それは本当に有用なスキム/読み物でした。
たまたま、昨夜、まさにこの主題に関する論文を読みました。著者は、Microsoft と IBM の 4 つのグループ内のプロジェクトを比較し、ユニット テストと機能テストの両方を使用したプロジェクトと、機能テストのみを使用したプロジェクトを後から比較します。著者を引用するには:
「ケース スタディの結果は、4 つの製品のプレビュー リリースの欠陥密度が、TDD プラクティスを使用しなかった同様のプロジェクトと比較して 40% から 90% 減少したことを示しています。主観的に、チームは初期段階で 15 から 35% の増加を経験しました。 TDD採用後の開発時間。」
これは、プロジェクトに新しい機能を追加するときに単体テストを行う価値があることを示しています。
はい、彼らはそれだけの価値があります。コードの単体テストを開始してから、コーディングが速くなりました。バグの修正に費やす時間が減り、コードで何をすべきかを考える時間が増えました。
単体テストは確かに余分な作業ですが、長期的には報われます。統合テストに対する利点は次のとおりです。
- リファクタリングの場合にセーフティネットとして機能する回帰スイートを取得します。統合テストについても同じことが言えますが、テストがコードの一部をカバーしているかどうかを判断するのは難しい場合があります.
- 単体テストは、コードを変更するとすぐにフィードバックを提供します。このフィードバックは非常に正確であり、異常のあるメソッドを示します。
- これらのテストは安価に実行できます。インストールやデプロイを行わずに、コンパイルしてテストするだけで、非常に高速に (通常は数秒で) 実行されます。そのため、頻繁に実行できます。
- 問題が特定されたら、その問題を再現するために新しいテストを追加するのは簡単です。また、回帰スイートを拡張したり、質問に答えたりすることもできます (「この関数が null パラメーターで呼び出されないとどうなるか...」)。
この 2 つには明らかに重複する部分がありますが、どちらにも利点があるため、補完的な関係にあります。
現在、あらゆるソフトウェア エンジニアリング プロセスと同様に、プロジェクトのニーズに合わせてテストを調整する必要があります。
大規模なレガシー コードベース (単体テストされていないという意味でのレガシー) では、単体テストを導入するのが難しい可能性があるため、コードに追加された新しい機能に限定して単体テストを行うことをお勧めします。この点に関しては、既存のコードベースに単体テストを導入するのに役立つ「レガシー コードを効果的に使用する」という本の推奨事項に 2 番目 (3 番目?) しかありません。
何かについて何かを知りたいときにテストします。製品 (システム、ユニット、サービス、コンポーネントなど) が機能することがわかっている場合は、テストする必要はありません。それが機能するかどうかわからない場合は、おそらくいくつかの質問があります。これらの質問に答える価値があるかどうかは、リスクと優先順位の問題です。
あなたの製品がうまくいくと確信していて、それについて何の疑問も持たない場合でも、まだ 1 つの価値のある質問があります: なぜ質問がないのですか?
---マイケル B.
21,000 行の switch ステートメントで構成された FAT (テスト) について相談するために、私が買収されたアプリケーションの 1 つです。ほとんどの機能単位は、case ステートメントで数十行から数百行でした。アプリケーションはいくつかのバリアントで構築されているため、スイッチには多くの #ifdef セクションがありました。
単体テスト用に設計されたものではなく、まったく考慮されていませんでした。
(明確で理解しやすいアーキテクチャがあるという意味で設計されました-構造体をmallocし、構造体へのポインタをlparamとしてメインループにユーザーメッセージを送信し、メッセージが処理されたときにそれを解放します。しかし、フォームはそうしました優れたデザインの中心的な信条である機能に従わない.)
新しい機能に単体テストを追加することは、パターンの大きな中断を意味します。大きなスイッチ以外の場所にコードを配置し、バリアント選択メカニズムの複雑さを 2 倍にするか、大量の足場を作成してメッセージをキューに入れて新しい機能をトリガーする必要があります。
そのため、新しい機能を単体テストすることは確かに望ましいことですが、システムがまだ十分に分解されていない場合、必ずしも実用的とは限りません。ユニット テストを可能にするためにシステムをリファクタリングするためにかなりの量の作業が必要になるか、コードをベンチ テストして既存のフレームワークにコピー アンド ペーストすることになり、ユニット テストされたコードのコピーはユニット テストされたコードではありません。