単体テストは作成と保守のコストが低くなりますが、すべてのシナリオをカバーしているわけではありません。それらの間の正しいバランスは何ですか?
8 に答える
これら 2 種類のテストの目的と範囲を区別することが重要です。
単体テストは通常、モジュール/クラス レベルで特定の機能をテストします。たとえば、create-X、update-Y、foo-the-bar、compact-the-whizbang などです。1 つのクラスに複数の単体テストを含めることができます。
「受け入れテスト」とも呼ばれる機能テストは、通常、最も外側のインターフェースから処理の最後まで、たとえばユーザーインターフェースからデータベースに戻り、入力プロセスから通知ユーティリティに戻るまでのユースケースシナリオをテストします。など
これら 2 種類のテストは互換性がなく、一般的に互いに関連性がありません。したがって、それらの間の「バランス」を取るという概念は意味がありません。あなたはそれらを必要とするか、必要としません。
テストフレームワークでの各タイプのテストのコーディングの容易さについて言及している場合、それは別の質問ですが、フレームワークの使用 (たとえば、NUnit とユーザーボット) は、テストのタイプ/性質を変更しません。テスト。
一般に、最適な「バランス」は、信頼性と完全性について単体テストを行い、クライアントの受け入れについて機能テストを行うことです。
ユニットテストと機能テストは非常に異なる目的で使用されるため、トレードオフがないという点でStevenLoweに同意します。
単体テストは、メソッドとタイプの検証、および回帰テストに関するものです。機能テストは、機能テスト、シナリオテスト、および実現可能性テストに関するものです。私の意見では、重複はほとんどありません、
それが役に立ったら、ここに私のテストカテゴリがあります。
開発者は、コードに焦点を当てて、内側から始めて外側に向かって作業します。
- アサーション-データフローと構造を確認します
- デバッガー-コードフローとデータを確認します
- ユニットテスト-各機能を検証します
- 統合テスト-サブシステムを検証する
- システムテスト-機能の検証
- 回帰テスト-欠陥が修正されたままであることを確認します
- セキュリティテスト-システムに簡単に侵入できないことを確認します。
テスターは、機能に焦点を合わせて、外側から始めて内側に向かって作業します。
- 受け入れテスト-エンドユーザーの要件を確認します
- シナリオテスト-実際の状況を確認します
- グローバルテスト-実行可能な入力を検証する
- 回帰テスト-欠陥が修正されたままであることを確認します
- ユーザビリティテスト-システムが使いやすいことを確認します
- セキュリティテスト-システムに簡単に侵入できないことを確認する
- コードカバレッジ-手付かずのコードのテスト
- 互換性-以前のリリースとの互換性
- 癖やラフなエッジを探しています。
エンドユーザーは外部から作業し、通常はほとんど焦点を合わせていません。
- 受け入れテスト-エンドユーザーの要件を確認します
- シナリオテスト-実際の状況を確認します
- ユーザビリティテスト-システムが使いやすいことを確認します
- 癖やラフなエッジを探しています。
私は、Brian Marick の自動テストに関する象限が好きです。ここでは、ビジネスとテクノロジーが直面し、サポート プログラミングと批判製品が区別されています。
そのフレームワークでは、バランスの問題が生じます。今何が必要ですか?
私の現在のプロジェクトは約 60% のユニット テスト カバレッジであり、すべてのユーザー ストーリーはセレン テストでのユーザー ストーリーのハッピーデイ カバレッジを持っており、いくつかは追加のカバレッジを持っています。
これについては継続的に議論しています: ますます不合理なシナリオの単体テストのカバレッジをプッシュして、より高いカバレッジを実現するポイントは本当にありますか?
Selenium テストを拡張すると、ビジネス価値のあるものに対するテスト カバレッジが増加するという議論があります。お客様は失敗する可能性のある単体テストのコーナー ケースを本当に気にかけていますか?
Selenium テストに慣れると、ビジネス価値のある新しいテストを作成するコストが減少します。私たちにとって、それらは単体テストと同じくらい簡単です。
ランタイム コストは別の問題です。これらのテストを常に実行しているボックスの小さなクラスターがあります。
そのため、Web テストをより好む傾向があります。これはおそらく、Web テストを作成するのが得意になり、否定できないビジネス価値を提供するためです。
テストは迅速に実行され、問題のローカライズに役立つ必要があります。単体テストでは、問題のモジュールのみをテストすることでこれを行うことができます。ただし、機能/統合/受け入れテストは、ほとんどの Web シナリオで十分に迅速に実行できます。
単体テストは「実行可能な要件」であると読んだことがありますが、これは私にとって完全に理にかなっています。テストがビジネス要件を証明することに重点を置いていない場合、テストはまったく役に立ちません。詳細な要件がある場合 (それが酸テストです)、多数の単体テストを作成して、考えられる各シナリオを実行し、データ構造のアルゴリズムとロジックの整合性を確認します。要件ではないものをテストしているが、テストに合格するには真でなければならないことがわかっている場合は、要件を満たしていない可能性が高くなります。
もともと私は、受け入れテストの初期コスト要因のために、機能/受け入れテストよりも単体テストを好むことに大きく傾いていました。しかし、時間の経過とともに私は自分の哲学を変え、今では可能な限り受け入れテストを選択し、受け入れテストが私のニーズを満たさない場合にのみ単体テストを使用することを強く支持しています。
単体テストよりも受け入れを選択する基本的な理由は、SOLIDの基本的な理由と同じです。コード。実装はリファクタリングなどで大幅に変更できる必要がありますが、すべてのビジネス ケース (受け入れテスト) は変更されずに維持され、受け入れ可能なシステム動作 (テストに合格) を証明できる必要があります。単体テストでは、多くの場合、テストと実装コードとの自然な強い結合があります。これはテスト コードですが、コードであり、ご存知のように強い結合は避ける必要があります。受け入れテストを選択することで、テストを強制的に変更することなく、舞台裏で実装を変更できる、よく計画された消費可能な分離された API を作成する成功のスパイラルに陥ることがよくあります。また、開発者の実装に関する考えは、ビジネス システムの動作に関する考えと一致しています。最終的には、これらすべてがビジネスとコーダーの満足度にとってより良いものであることがわかりました。
理論的な観点から、コードの一部が受け入れテストでテストできない場合、なぜそのコードが存在する必要があるのか と自問することがよくあります。IE - 有効なビジネス シナリオの一部ではない場合、そのコードは付加価値がありますか?それとも現在のコードであり、コストのみで維持されますか?
さらに、受け入れテストを適切にコメント/文書化する場合、それらのコメント/文書は通常、システムの最新かつ正確な言語です。これにより、通常、他のあまり価値のない文書化アプローチを回避できます。単体テストは、そのような形式の「ビジネス用語」コミュニケーションには向いていません。
最後に、私はこの視点を個人的な開発だけから形成したわけではありません。私の「非常に企業的な」作業環境で、いくつかの異なるプロジェクト チームで成功したことが証明されています。
私が現在取り組んでいるアプリでは、おそらく 10:1 単位で機能テストが行われます。単体テストは、DB からのエンティティの取得、データベース/ネットワーク接続のエラー処理テストなどの単純な作業です。これらは数分以内に実行され、開発者によって毎日実行されます。
機能テストはキッチンシンクのアプローチになる傾向がありますが、ユーザーは完全な注文などを行うことができますか? これらは実行に数週間かかり、通常はリリース サイクルを完成させます。