単体テストをどのように設計するか?
単体テストの設計方法論
単体テストケースは通常のテストケースの設計とあまり変わりませんが、共通するのは同値クラス分割と境界値分析です。テスト ケースの設計は、実際には開発者が習得すべき基本的なスキルです。
等価クラス分割
すべての入力をいくつかのカテゴリに分割し、各カテゴリから少数の代表的なデータをテスト ケースとして選択します。
たとえば、入力引数の絶対値の逆数を計算するメソッドは、入力が 0 の場合に例外をスローします。次に、このメソッドのテストを作成する場合は、3 つの等価クラスがあり、入力は負、0、正である必要があります。したがって、負の数、正の数、0 を選択して 3 つのテスト ケースを設計できます。
別の例として、医師の認定ステータスに応じて異なるメッセージを送信するメソッドがあります。この場合、等価クラスには、非認証、通常認証だが権限認証なし、通常認証と権限認証の 3 種類があり、場合によっては通常認証なしで権限認証が含まれる場合もあります。
境界値解析
境界値は、同値クラスが分割された後の境界付近の入力データを指します。これらの入力は多くの場合、最もエラーが発生しやすいものです。
たとえば、絶対値の逆数を計算する上記の例の場合、境界値には Integer.min、-1、0、1、Integer.max などが含まれます。別の例として、テキスト ボックスの入力範囲が 1 ~ 255 文字の場合、等価クラスは入力の長さに応じて 0、1 ~ 255、および 255 より大きい 3 つのタイプに分割されますが、境界値には 0 が含まれます。 、1、2、254、255、256等。
空の配列、配列の最初と最後、レポートの最初と最後の行なども境界値であり、特別な注意が必要です。
その他の方法
上記のいくつかに加えて、一般的に使用されるテスト設計方法がいくつかあります。
シーンメソッド。シナリオメソッドは、実際のAPIの呼び出しメソッド、システムの実際の需要シナリオ、処理ロジックによって作成されるユースケースなど、モジュールの実際の使用法に基づいています。この方法はより直感的であり、ユースケースは実際の需要に近いため、無視できません。
間違った推測です。間違いは実際には直観に基づいており、最も間違いが起こりやすい状況を考慮してユースケースを設計します。たとえば、新規ユーザー、繰り返しのリクエスト、同時実行性、脆弱なネットワーク、大量のデータなどが発生するまでは非常にエラーが発生しやすいため、ターゲットを絞った方法でユースケースを設計できます。エラーの推測を行うには、テスト設計者がビジネス ロジックに精通しており、豊富な経験を持っている必要があります。
因果関係図や直交法などの他の方法もありますが、ここでは説明しません。
カバレッジ
前述のユースケース設計方法に従えば、多くのユースケースを設計できます。すべてのユースケースを単体テストとして記述することは不可能であり、その必要もありません。
ユースケースが十分かどうかを確認するにはどうすればよいですか? 非常に重要な参照指標はコード カバレッジです。
カバレッジメトリクス
一般的に使用されるカバレッジ指標は次の 4 つです。
ステートメント カバレッジ: すべてのステートメントが少なくとも 1 回実行されます。
ブランチ カバレッジ: 各ブランチは少なくとも 1 回は true と false になります。
条件カバレッジ: 各ブランチの各条件は、少なくとも 1 回は true であり、少なくとも 1 回は false です。
パス カバレッジ: 分岐やループなどの考えられるすべてのパスを少なくとも 1 回はカバーする必要があります。
この単純なコードを例として、4 つのカバレッジが何を意味するかを見てみましょう。
if (a && b) {
// バツ
}
//はい
if (c || d) {
// バツ
}
ステートメントの報道。必要なテスト ケースは 1 つだけです。a && b と c || d を true とすると、システムは X、Y、Z の 3 つのコード セグメントを順番に実行してステートメント カバレッジを達成します。
支店のカバレッジ。a && b と c || d を true と false の両方にするには、少なくとも 2 つのテスト ケースが必要です。たとえば、ユース ケース 1 a && b は true、c || d は false で、ユース ケース 2 は逆になり、両方が許可されます。条件 各分岐は 1 回 true と 1 回 false になります。
条件はオーバーライドされます。少なくとも 4 つのテスト ケースが必要で、条件 a と b の 4 つの組み合わせすべてが 1 回実行され、条件 c と d の 4 つの組み合わせもすべて 1 回実行されます。
パスのカバレッジ。少なくとも 8 つのテスト ケースが必要で、条件 a、b、c、d のすべての組み合わせが 1 回実行されます。
条件付きカバレッジ、さらにはパス カバレッジを達成するには、多くのテスト ケースが必要であることがわかります。一般に、複雑なロジックの場合は、単体テストで分岐カバレッジを実行し、必要に応じてより完全なカバレッジを実行することをお勧めします。
ジャココの取材
Jacoco の報道内容は少し異なります。ここで簡単に紹介します。
命令カバー (命令) は、すべての Java コード命令をカバーします。
ブランチカバレッジ(Branches)と上記のブランチカバレッジは基本的に同じです。
循環的複雑さはパス カバレッジと考えることができます。
ステートメント カバレッジ (行) は、基本的に上記のステートメント カバレッジと同じです。
メソッド カバレッジ (メソッド)、すべてのメソッドをカバーします。
クラス カバレッジ (クラス)、すべてのクラスをカバーします。
効果的な単体テストを作成するにはどうすればよいでしょうか?
ここまでで、誰もが単体テストの書き方についてある程度のアイデアを持っているはずです。しかし、多くの人は次のような疑問も抱いています。
単体テストに時間がかかりすぎると、生産性が低下しますか?
単体テストの保守は難しいですか? たとえば、コードを変更する場合は、必ず単体テストを変更する必要があります。
最初の質問については、開発中にバグを発見した場合、それを解決するのは簡単ですが、統合され、受け入れられ、さらには立ち上げられると、解決するのに多大なコストがかかることは誰でも理解できると思います。業界には長い間コンセンサスがあり、効果的な単体テストにはコーディング時間が長くかかるものの、プロジェクトの統合、テスト、およびメンテナンスのコストを大幅に削減できることを証明するデータが数多くあります。
単体テストが効果的である必要があることに注意することが重要です。単体テストの保守が難しいと感じる場合、それは多くの場合、効果的な単体テストを作成していないことが原因です。
すべてのコードに単体テストが必要なわけではない
単体テストを書く際には入出力比も考慮する必要があり、例えば次のような状況では単体テストを書く際の入出力比が悪い可能性があります。
デモ、データ更新スクリプトなどの短期または 1 回限りのプロジェクト。
シンプルなビジネスを備えた、あまりロジックのないモジュールです。たとえば、分岐条件のないデータやビジネス ロジックを取得または検索する場合などです。
UI 自体がより複雑なロジックを持っていない限り、UI 層で単体テストを行うのは比較的困難です (実際、一部の UI フレームワークは単体テスト ツールも提供しています)。
では、そのような場合に単体テストを作成するとどうなるでしょうか? 簡単に言うと2種類あります。
複雑なロジックを備え、理解するのが難しく、エラーが発生しやすいモジュール。たとえば、閏年の計算方法や注文方法などです。
パブリック モジュールまたはコア ビジネス モジュール。
単体テストを記述する必要があるモジュールであっても、コアで最も重要なテスト ケースに焦点を当てる必要があり、単にカバレッジを追求する必要はなく、条件付きカバレッジやパス カバレッジさえも追求する必要はなく、通常はブランチ カバレッジで十分です。もう 1 つの効果的な方法は、発生したバグごとに単体テストを追加することです。
単体テストは安定しているはずです
ここでの安定性の最初の意味は、単体テストを頻繁に変更する必要がないということです。基礎となる実装ロジックの変更により単体テストを頻繁に変更する必要がある場合、それは優れた単体テストではないはずです。つまり、テスト対象ユニットのインターフェイスは安定していて、適切に設計されており、拡張が容易である必要があります。
安定の 2 番目の意味は、単体テストの結果が安定している必要があることです。異なる環境や異なる状況で単体テストを実行し、異なる結果が返された場合、それは優れた単体テストとは言えません。テストが特定のデータやファイルなどに依存する必要がある場合は、依存するデータやファイルが存在し、すべての環境で一貫していることを確認するために、事前初期化スクリプトが必要です。
単体テストはグレーボックステストであるべきです
単体テストでは、コア ロジックのさまざまな分岐、境界、例外をカバーする必要がありますが、揮発性の実装ロジックが関与することは避けてください。つまり、単体テストは完全なホワイトボックステストではなく、ブラックボックステストではなく、ホワイトボックスとブラックボックスの中間のグレーボックステストと考えるべきです。
テスト対象のコードは十分に抽象化されている必要があります
コードの一部が単体テストを書くのが難しいとわかった場合、そのコードが適切な抽象仕様に準拠していないことが原因であることがよくあります (DI を使用していない、単一責任の原則に準拠していない、またはグローバル パブリック変数に依存しているなど)。や方法など。このコードの最適化を検討してから、単体単体テストを試してみましょう。
抽象化とは何か、そしてソフトウェア設計の抽象原則について話すと、ソフトウェア抽象化の原則が紹介されるため、ここでは繰り返しません。
コーディングするときは単体テストも同時に作成する必要があります
このようにして、デバッグ時に単体テストを活用し、コードの変更に関するフィードバックを即座に得ることができます。単体テストを後から追加すると、実装に慣れていない可能性があり、テスト作成のコストが高くなる一方で、単体テストが果たせる役割も小さくなります。しかし、それでも、単体テストの作成は、長期的なメンテナンスが必要なプロジェクトには依然として役立ちます。
単体テストのコード品質も重要
単体テストもコードであるため、継続的にメンテナンスする必要があります。したがって、高い品質、モジュール性、保守性を実現するには、単体テストを安易に作成せず、通常のコードとして扱う必要があります。
単体テストを作成する必要がある究極の理由
究極の理由は、優秀なエンジニアとして、QA およびプロダクト マネージャーのチャレンジにバグがあった場合、耐えられるかどうかということです。そしてもちろん、私たちのエンジニアはエンジニアスタイルのテスト方法、つまり自動化された単体テストを使用する必要がありますね。
記事の出典: ネットワークの著作権は原作者に帰属します
上記のコンテンツは営利目的ではありません。知的財産権に関する問題が含まれる場合は、編集者にご連絡ください。すぐに対処します。