ユニット 6 / 12

テストの自動化と品質保証

利益:

  • AI を使用して意味のあるアサーションを含む単体テスト、統合テスト、およびエッジケース テストを作成する機能
  • AI サポートにより、テスト カバレッジ、制限値、ネガティブ シナリオを体系的に抽出する機能
  • AI によって生成されたテストが既存のコードを繰り返すだけではなく、実際に動作を検証していることを検証する機能

テストは、ソフトウェアが実際に約束どおりに動作することを証明するメカニズムです。優れたテストスイートでは、変更によって何かが損なわれるかどうかが数秒でわかり、エンジニアは自信を持って行動することができます。 AI は、テスト作成の最も退屈でスキップされがちな部分、つまり多数のシナリオ、ブレークポイント、ネガティブ ケースの生成を高速化します。しかし、ここには卑劣な罠があります。AI は、コードの想定される動作ではなく、現在の (おそらく欠陥のある) 動作を検証するテストを作成する可能性があります。または、実際には何もチェックせずに、常に合格する空のテストを生成することもできます。テストの価値は、合格するかどうかではなく、正しいことをチェックし、間違っている場合に赤信号になるかどうかにあります。

この単元では、意味のあるアサーションを使用して単体テスト、統合テスト、およびエッジ ケース テストを作成する方法を学びます。テストカバレッジ、ブレークポイント、ダウンサイドシナリオを体系的に抽出する方法。そして、AI が生成するテストが実際に動作を検証していることを確認する方法を見ていきます。

概念: 単体テスト: 単一の関数/クラスを分離してテストします。統合テスト: 複数の部分が正しく連携して動作するかどうかをテストします。 Assert: 結果が期待されたものと等しいかどうかを確認するステートメント。これがテストの核心です。カバレッジ: テストによって実行されるコードの量。カバレッジが高いからといって品質が保証されるわけではありません。

意味のあるテストを作成する

優れたテストは、状態を確立し、アクションを実行し、結果を表明するという 3 つのことを明確に実行します。 AI にテストを出力するときは、どのような動作を検証するか、どのようなシナリオをカバーする必要があるかを指定します。それ以外の場合は、常に合格する表面的なテストが生成されます。

  1. テストする動作を定義します。 「何が正しいと考えられますか?」質問に明確に答えてください。
  2. シナリオの種類を尋ねます。正常、限界、負、エラー状態。
  3. 意味のあるアサートをインポートします。単に「エラーをスローする」のではなく、「正しい値を返す」のです。
  4. テストの精度を確認します。意識的にコードを破るとテストは赤くなりますか?

包括的なテスト生成プロンプト: 「次の 'applydiscount(amount, Coupon)' 関数の単体テストを作成します。次のカテゴリに少なくとも 1 つのシナリオがあります: (1) 通常の有効なクーポン、(2) ブレークポイント (0 金額、100% 割引)、(3) ネガティブ (無効なクーポン、マイナスの金額)、(4) エラー ケース (null クーポン)。各テストで具体的な期待値をアサートします (単に「機能した」だけではありません)。テストに名前を付けます。コード: [コード]」

境界値抽出プロンプト: 「この関数の入力に対して境界値分析を実行します。パラメーターごとに、「境界のすぐ上」、「境界のすぐ下」、「境界のすぐ上」の値をテーブルとして抽出します。次に、これらの境界をカバーするテスト シナリオをリストします。コードはまだ記述せず、分析とシナリオのリストだけを作成します。関数: [署名]"

注意: 高いテスト カバレッジ (例: 90%) は、コードが正しいことを証明するものではありません。カバレッジは実行された行数を測定します。これらの行が正しい結果を生成するわけではありません。意味のあるアサートのないテストはカバレッジを高めますが、何も保証しません。アサーションの数ではなく、アサーションの内容によって品質が決まります。

テスト自体のテスト: 突然変異のロジック

AI が生成したテストが実際に機能するかどうかを理解する最も現実的な方法は、意図的にコードを破壊すること (突然変異テスト ロジック) です。条件を反転し、+ 記号を - にします。赤に変わるテストがない場合、テストは実際にはその動作を維持していません。

脆弱性ハンティングのテスト プロンプト: 「次のテストではキャッチできない可能性があるこのコードの潜在的なバグを教えてください。コードに加えられる可能性のある 5 つの小さな変更 (例: > の代わりに >=、+ の代わりに -) を提案し、それぞれについて既存のテストでキャッチできるかどうかを示します。キャッチされなかったものについては、追加する必要があるテストを提案してください。コード: [コード] テスト: [テスト]」

弱いプロンプト / 強いプロンプト

WEAK: 「この関数にテストを作成します。」 (結果: 通常は 1 つの正常なシナリオ、弱いアサート、エラーは見逃されます。) STRONG: 「この 'passwordStrong' 関数にテストを作成します。ルール: 少なくとも 8 文字、大文字 1 文字、数字 1 文字が必要です。次のシナリオを SEPARATE テストとしてカバーします: 正確に 8 文字 (制限)、7 文字 (制限未満)、大文字なし、数字なし、空の文字列、スペースのみ、長すぎます (1000 文字) 予期したものを明示的にアサートします各テストの true/false 値を指定し、チェック内容に応じてテストに名前を付けます。」

強力なプロンプトにより、ルールと完全な境界シナリオが提供されます。 「ちょうど 8 / 7 文字」のような境界ペアは、最もよく間違いを犯しやすい場所です (> と >= の混同)。弱いプロンプトはこれらの境界を回避し、エラーを運用環境に伝えます。

テストの種類と使用場所

テストの種類

それは何を裏付けるのでしょうか?

AIの貢献

注意

ユニット

単一の関数/クラス

マルチシナリオを高速に生成

意味のあるアサートが必要です

統合

パーツが連携して動作する

シナリオとモックデータのドラフト

真の依存行為

終了/承諾

ユーザーフロー全体

ステップリストと期待

脆くなりやすい

回帰

古いエラーが返らない

障害固有のテスト

すべての修正に追加する必要があります

ミニケース

ケース 1 — 常に合格するテスト。 AI は 12 個のテストを関数に書き込み、すべて合格します。エンジニアは疑念を抱き、関数の戻り値を意図的に歪めます。テストのうち 3 つだけが赤になります。他の 9 つのテストには意味のあるアサートが含まれていません。検査は突然変異探索によって強化されます。実際の保護は 9 つのシナリオで得られます。

ケース 2 — 境界エラー。年齢認証機能では「18 歳以上有効」と表示されるはずですが、>18 と書かれており、18 歳は拒否されます。 AI がブレークポイント分析を通じて「ちょうど 18」のシナリオを生成するため、テストではエラーがすぐに表示されます。単一の限界テストにより、実際のユーザーからの苦情が防止されます。

ケース 3 — 現在の動作を修正します。 AI が「このコードに基づいてテストを書く」ように指示されると、コード内にすでに存在する丸め誤差を「正しい」ものとして受け入れるテストを生成します。エンジニアがコードではなく要件 (期待される正しい値) に従ってテストを印刷すると、テストが赤になり、実際のエラーが発生します。テストはコードからではなく、期待から導き出される必要があります。

よくある間違い

  • 無意味な主張。 「エラーをスローしませんでした」だけでは十分ではありません。正しい値を確認する必要があります。
  • 範囲と品質が混同されている。カバレッジが高いからといって、正確な結果が保証されるわけではありません。
  • コードによるテストの印刷。現在のエラーを「true」に修正します。テストは期待に基づいて行われる必要があります。
  • 制限値をスキップします。 > と >= を混同するのは最も一般的な間違いです。境界ペアをテストする必要があります。
  • テスト自体を監査しません。コードを解読しても赤にならないテストは保護を提供しません。

要約すると

優れたテスト スイートは、自信を持って変更を加えるための鍵となります。 AI は、多数のシナリオ、限界、否定的な状況を迅速に生成します。しかし、要件ではなくコードからテストを導き出す場合は、既存のバグを修正したり、常に合格する無意味なテストを作成したりできます。各テストで具体的な期待値をアサートし、バインドされたペアを含め、意図的にコードを破壊することでテストが実際に保護していることを検証します。スコープの数ではなく、アサートの内容が品質を決定します。

アプリケーションタスク

関数を選択すると、包括的なテスト生成プロンプトを使用して 4 つのカテゴリ (正常、限界、陰性、エラー) のテストを生成します。各テストで具体的な期待値をアサートしてください。次に、テストの脆弱性ハンティング プロンプトを実行し、コード内の 5 つの小さな変異を提案し、テストを実行してどれが検出されるかを確認します。捕捉されなかった少なくとも 1 つの突然変異に対する新しいテストを追加し、現在赤字であることを示します。

チェックリスト

  • [ ] コードではなく、予想される/正しい動作に基づいてテストを印刷しました。
  • [ ] 通常、限界、ネガティブ、エラーのシナリオについて説明しました。
  • [ ] 各テストにおける具体的な期待値を主張しました。
  • [ ] 境界ペア (直上-直下 / 直上-直下) をテストしました。
  • [ ] 意図的にコードを壊すことで、テストが赤くなることを確認しました。
  • [ ] 未検出の突然変異に対する新しいテストを追加しました。