ユニット 6 / 11

単体テストの生成とテスト容易性: AI を使用した堅牢なテスト

利益:

  • 受入れルールとは独立して単体テストの期待値を計算することで、人工知能が誤った動作を「正しい」ものとして受け入れるのを防ぐ機能
  • AAA および FIRST 原則を適用し、外部依存関係をモックすることにより、高速で独立した反復可能なテストを印刷する機能
  • ミューテーション (コード破壊) を含むテストをテストし、テストが難しいコードをデザイン臭として認識する能力

テスト ピラミッドの最大かつ最速の層は単体テストです。これは、関数またはコードの小さな部分を他のすべてから分離して検証するテストです。何千もの単体テストが数秒で実行され、コードが開発者の画面に表示されている間にバグを発見します。人工知能 (AI) は、おそらく単体テストの作成に最も熟練しています。機能を与えると、AI が数十のテストを作成します。しかし、この利便性こそが最大の罠を生むのです。AI は簡単に「緑色に光るが何も検証しない」テストを生成したり、コードの現在の (おそらく欠陥のある) 動作を「正しい」ものとして受け入れたりします。この単元では、AI を使用して真に保護的な単体テストを作成する方法と、テスト可能なコードと AI の関係について学びます。

優れた単体テストの性質: 第一に

優れた単体テストは、FIRST の原則に従います。高速、独立性 (テストが互いに依存すべきではない)、反復可能 (反復可能 - どの環境でも同じ結果)、自己検証 (合格/不合格が明確)、タイムリー (時間通り)。 AI にテストを作成させるときは、これらの原則を思い出してください。特に、テストが「独立」かつ「反復可能」であるために外部の世界(実際のデータベース、ネットワーク、クロック)に依存しないことを要求します。

AAA パターンと表現力豊かな主張

堅実な単体テストは AAA 構造に従います。Arrange (準備 – 入力と依存関係を設定する)、Act (実行 – テスト対象の関数を呼び出す)、Assert (検証 – 結果を期待値と比較する)。重要なのはアサートです。 AI が犯す最も一般的な間違いは、テスト対象のコードの出力からアサートを導き出すことです。これは、「コードが返すものはすべて true」というロジックです。これではテストの意味がなくなってしまいます。正しい方法は、期待値を独立して決定することです (許容基準から手動で計算します)。

注意: AI に「この関数のテストを書いて」と指示すると、AI は関数を実行し、その出力を「期待どおり」として書き込む可能性があります。このテストは、関数が false であっても合格します。代わりに、「これらのルールに従って期待される結果を計算し、関数の現在の出力を参照しないでください。」と言いましょう。

モック、スタブ、依存関係

単体テストには分離が必要です。関数がデータベースまたは API に依存している場合、それらはテスト時にモック オブジェクト (モック/スタブ - 実際の依存関係を制御されたダミーの代替品) に置き換えられます。これにより、テストが迅速かつ独立して再現可能になります。 AI は模擬インストールを作成できます。ただし、過剰なモックには注意してください。すべてをモックすると、テストでは実際のロジックではなく、「モックが返すもの」のみが検証されます。バランス: 外部の世界をエミュレートし、テスト対象の実際のロジックを実行します。

テスト容易性と AI

興味深いフィードバックがあります。テストが難しいコードは、多くの場合、設計が不十分なコードです。 AI が関数へのテストを書くのに問題がある場合 (依存関係が多すぎる、隠されたグローバル状態、副作用)、それは設計の臭いです。 AI に「このコードをテスト可能にするためにどのようにリファクタリングしますか」と尋ねることは、より良いテストとより良いコードの両方につながります。

パラメータ化されたテストとデータの多様性

異なる入力で同じルールを検証するために毎回別のテストを作成するのは面倒であり、保守も困難です。パラメーター化されたテスト (入力と期待される結果のリストに対して同じテスト ロジックを繰り返し実行する構造) では、この繰り返しを排除します。単一のテスト本体に数十の入力ペアが供給されます。 AI は、受け入れルールを与えると、これらの入力と期待される結果テーブルを非常に効率的に生成します。特に、限界値と等価クラスを体系的に表にします。

しかし、ここにも落とし穴があります。AI は、テスト対象のコードから生成されたテーブルで期待される結果を導き出す傾向があります。単一の間違ったロジックが数十行を無効にするため、パラメータ化されたテストではこのエラーはさらに危険です。したがって、期待される結果の列を常に受け​​入れルールに従って個別に計算し、少なくとも数行を手動で検証してください。また、「各行が何を表しているか」という説明列も求めます。そのため、行が壊れると、どの状態が壊れているのかがすぐにわかります。

ヒント: パラメータ化されたテスト テーブルに意図的に「トラップ行」を追加します。つまり、意図的に結果を誤って入力します。テストの実行時にその線が赤にならない場合、テストは実際にその状況を検証していません。これは簡単な模擬合格チェックです。

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

弱: 「この関数の単体テストを作成します。」
強力: 「taxCalculate(amount, rate)」関数の [言語/フレームワーク] 単体テストを作成します。受け入れルール: 結果 = 金額 * レート、小数点以下 2 桁に四捨五入します。負の金額またはレートはエラーをスローします。レートが 0 の場合は 0 を返します。AAA 構造を使用します。これらのルールに従って期待値を手動で計算します。関数の現在の出力を参照しません。限界と負のケース (0、負、非常に大きい、小数点以下に四捨五入) をカバーします。それぞれの名前を使用します。 test は検証するルールを説明します。「いいえ」。

強力なプロンプト。それは、受け入れルール、独立した期待値の期待、構造、およびエッジケースを提供します。したがって、テストはコードの鏡ではなく、ルールの保護者になります。

単体テスト品質テーブル

症状

悪いテスト (偽の信頼)

良いテスト

主張する

なし、または「null ではない」

具体的な期待値

期待値のソース

関数の出力

受け入れルール/手動計算

依存症

実際の DB/ネットワーク/時間

モック/スタブで絶縁

エッジケース

幸せな道だけ

限界、負、エラー

コードを壊すと

緑色のまま

赤くなる

名前

テスト1、テストメソッド

確認するルールを説明します

コピー可能な 4 つのテンプレート

1) ルール主導の単体テスト:

あなたの役割: シニア ソフトウェア テスト エンジニア。[言語/フレームワーク]: [署名] を使用して次の関数の単体テストを作成します。受け入れルール: [ルール]。- AAA 構造を使用します。- これらのルールに従って期待値を手動で計算します。 関数の現在の出力を参照しないでください。 - 限界、ネガティブ、エラー、ハッピーパスを個別のテストでカバーします。 - 各テスト名には、検証するルールを記述します。 - 外部依存関係を模擬します。実際のロジックを動作させます。

2) 突然変異耐性の制御:

これらの単体テストを確認してください。テスト対象のコードに加えることができる 5 つの小さな調整 (+ の代わりに -、> の代わりに >=、境界シフト) をリストし、それぞれについて、これらのテストのうちどれが赤色になるかを教えてください。何も返されない場合、テストは不十分です。コード + テスト: [貼り付け]

3) テスト容易性のレビュー:

この関数の単体テストを書くのが難しいのはなぜですか?隠れた依存症、世界的地位、副作用、多くの責任がありますか?テスト可能にするために最小限のリファクタリングを提案します。行動を変えないでください。コード: [貼り付け]

4) 不完全なシナリオの完了:

以下の機能と利用可能なテストが提供されます。どの動作/エッジケースがテストされていないのか (スコープ ギャップ) をリストし、それぞれのテストを追加します。関数+テスト: [貼り付け]

ミニケース3個

ケース 1 — コードのミラーリングをテストします。開発者は AI に丸め関数のテストを作成させました。 10 個のテストが緑色でした。実際、関数は間違った方向に丸めていましたが、AI は関数の出力から期待値を取得していたため、テストではエラーが「真」であると見なされていました。 「ルール駆動」テンプレートを使用して期待値を手動で計算すると、4 つのテストが赤になり、実際のエラーが明らかになりました。

ケース 2 — 突然変異制御の価値。あるチームは 45 の単体テストに依存していました。 「突然変異の堅牢性チェック」を使用してコードに 20 の小さな調整を試みました。テストではそのうち 11 件しか検出されませんでした。残りの9回の混乱は静かに過ぎ去った。チームは弱いテストを強化した。実際の計算エラーは、次のリリースのこれらの強化されたテストによって検出されました。

ケース 3 — テスト不可能性はデザインの臭いです。 AI は順序付け関数のテストを作成できず、常に実際のデータベースが必要でした。 「テスト容易性レビュー」テンプレートは、組み込みデータベースにアクセスする機能を示しました。依存関係の注入が削除されると、テストを作成できるようになり、コードがすっきりしました。

よくある間違い

  • コードから期待値を導き出す。 AI は関数の出力を「正しい」ものとして受け入れます。欠陥のあるコードを確認するテスト。
  • アサートなしまたは簡単なアサートを使用してテストします。 「彼はエラーをスローしなかった、パスした」ロジック。それは何も確認しません。
  • 極端なモック。すべてをモックし、モックが返すものだけをテストします。実際のロジックはテストされません。
  • まさに幸せな道。リミット、ネガティブ、エラー状態をバイパスします。
  • コードを壊してテストするわけではありません。突然変異をチェックせずに緑を信頼する。
  • テスト不可能性を無視します。厳しいテストを進める代わりに、悪い設計を認識して修正しない。

要約すると

単体テストは、テスト ピラミッドの中で最も高速かつ最大の層です。最も安い瞬間にミスをキャッチします。 AI は単体テストを作成する能力が非常に優れていますが、その最大の落とし穴は、コード自体から期待値を導き出すことで、誤った動作を「正しい」とみなすテストを作成することです。解決策: 受け入れルールを与え、期待値を手動で計算させ、AAA と FIRST の原則を適用し、外部の世界をモックして実際のロジックを実行し、ミューテーション (コードの破壊) によって各テストをテストします。テストが難しいコードは、修正が必要な設計の兆候です。

アプリケーションタスク

独自のプロジェクトからビジネス ルールを含む関数を選択します。受け入れルールを作成し、AI に「ルール駆動の単体テスト」テンプレートを使用してテストを作成させます。期待値は手動で計算してください。次に、「突然変異の堅牢性チェック」を適用します。コードに少なくとも 5 つの小さな中断を作成し、赤になったテストの数を測定します。捕捉されなかった破損に対する新しいテストを追加します。捕捉された中断の数 (突然変異スコアなど) を報告します。

チェックリスト

  • [ ] 受け入れルールを与え、期待値を手動で計算させました。
  • [ ] テストがコードから期待値を導き出していないことを確認しました。
  • [ ] 私は、AAA および FIRST ガイドラインに従って独立したテストを確立しました。
  • [ ] 外部依存関係をモックし、実際のロジックを実行しました。
  • [ ] リミット、ネガティブ、エラーのケースについて説明しました。
  • [ ] コードを破壊 (突然変異) することで、テストが実際に保護することを証明しました。