突然変異テストとは何ですか? (例)

⚡ スマートサマリー

ミューテーションテストでは、ソースコードに意図的に小さな欠陥を導入し、既存のテストスイートを欠陥のあるすべてのバージョンに対して実行し、それらのテストが変更を検出するのに十分な強度を持っているかどうかを測定します。

  • 🔘 定義: 変異体とは、意図的に構文上の変更を加えたプログラムのことであり、それを終了させることで、その変更を検出したテストが成功したことを証明できる。
  • ☑️ プロセス: 変異体を生成し、元のテストと変異体に対してテストスイートを実行し、出力を比較し、欠陥を見落としたテストを強化する。
  • Operators: Operand置換、発現修飾、およびステートメント修飾は、3つの主要な変異体ファミリーを生み出す。
  • 🧪 スコア: 変異スコアは、殺された変異体の割合であり、単なる行の実行ではなく、主張の強さを測定するものです。
  • 🛠️ ツーリング: ストライカーカバー Javaスクリプト、 TypeScript、C#、Scala であり、PIT は Maven 内の JVM バイトコードを変更し、 Gradle ビルド。
  • ⚠️ 費用: 変異体ごとにテストスイート全体が再実行されるため、自動化なしでは変異テストは時間がかかり、費用も高く、実用的ではない。

突然変異テスト

突然変異テストとは何ですか?

突然変異テスト ミューテーションテストとは、ソースコードの特定の記述を変更(ミューテーション)して、テストケースがソースコードのエラーを検出できるかどうかを確認するソフトウェアテストの一種です。ミューテーションテストの目的は、テストケースの堅牢性を確保し、変更されたソースコードに対してテストケースが失敗するようにすることです。

ミューテーションプログラムに加えられる変更は、プログラム全体の目的に影響を与えないように、極めて小さく抑えなければなりません。ミューテーションテストは、意図的にプログラムに欠陥を作り出すため、欠陥ベースのテスト戦略とも呼ばれます。これは、 ホワイト Box テスト 主に適用されるのは 単体テスト.

突然変異テストは、1971 年にリチャード・リプトンによる学生論文で提案され、1978 年にデミロ、リプトン、セイワードによる論文「テストデータ選択のヒント」で形式化されました。当時の計算コストのために勢いを失いましたが、その後、次のような言語で再び勢いを取り戻しました。 Java、C#、 Python, JavaスクリプトとXML。

ミューテーションテストを実行するにはどうすればよいですか?

変異テスト(変異解析とも呼ばれる)を実行する手順は以下のとおりです。

ステップ1: プログラムのソースコードに欠陥を導入するために、ミュータントと呼ばれる多数のバージョンを作成します。各ミュータントには単一の欠陥が含まれている必要があり、テストケースの有効性を実証するために、ミュータントバージョンを失敗させることが目標です。

ステップ2: テストケースは元のプログラムと変異プログラムの両方に適用されます。 テストケース は適切であるはずであり、プログラム内の障害を検出するために調整されています。

ステップ3: 元のプログラムと変異プログラムの結果を比較してください。

ステップ4: 元のプログラムと変異プログラムが異なる出力を生成する場合、変異プログラムはテストケースによって排除されます。したがって、このテストケースは元のプログラムと変異プログラム間の変更を検出するのに十分です。

ステップ5: 元のプログラムと変異プログラムが同じ出力を生成する場合、変異プログラムは生存したままとなる。このような場合、すべての変異プログラムを排除できる、より効果的なテストケースを作成する必要がある。

下の図 trac元のプログラムから突然変異体の生成、そして殺されるか生き残るかの判決まで、同じ5つのステップを踏む。

変異テストのワークフロー。元のプログラム、生成された変異体、テストの実行、および変異体の生存または死滅判定を示す。

突然変異プログラムを作成するにはどうすればよいですか?

変異とは、プログラム文に加えられる単一の構文変更に他ならない。各変異プログラムは、元のプログラムと正確に1つの変異だけが異なるべきである。

オリジナルプログラム ミュータント プログラム
(x>y) の場合
「こんにちは」を印刷する

「こんにちは」を印刷する
もし(x)
「こんにちは」を印刷する

「こんにちは」を印刷する

上記のペアでは比較演算子のみが変更されていますが、x が y より大きいテストケースでは、「Hello」ではなく「Hi」と表示されます。この図は、1 つの構文変更を示しています。

1つの構文変更をプログラムステートメントに適用して、単一の変異体を生成した。

ミュータント プログラムでは何を変更する必要がありますか?

変異プログラムを生成するために使用できる手法はいくつかあります。以下の3つのファミリーは、ツールに付属するほとんどの変異演算子を網羅しています。

Operand置換演算子 式変更演算子 ステートメント変更演算子
オペランドを別のオペランド(xをyに、またはyをxに)または定数値に置き換えます。 プログラム文内の演算子を置換するか、新しい演算子を挿入します。 プログラムステートメントは、突然変異したプログラムを作成するために変更されます。
例:
If(x>y) x と y の値を置き換えます
If(5>y) x を定数 5 に置き換えます
例:
If(x==y)
== を >= に置き換えると、ミュータントプログラムは次のようになります。
If(x>=y) とステートメントに ++ を挿入する
If(x==++y)
例:
if-else ステートメントの else 部分を削除する
プログラムの動作を確認するために、if-else文全体を削除してください。

変異演算子の例をいくつか挙げます。

  • GOTOラベルの交換
  • return ステートメントの置換
  • ステートメントの削除
  • 単項演算子の挿入(例:- および ++)
  • 論理コネクタの交換
  • 同等の配列名の置換
  • if-else文のelse部分を削除する
  • オペレーターの追加または置換
  • データ変更によるステートメントの置換
  • 変数のデータ変更
  • プログラム内のデータ型の変更

Opera境界条件に接触する変異体は最も頻繁に生き残るため、突然変異の結果はしばしばギャップを指摘する。 境界値解析.

突然変異テストの種類

In ソフトウエアエンジニアリングミューテーションテストは、基本的にステートメントミューテーション、値ミューテーション、および決定ミューテーションの3種類に分類されます。

  • ステートメントの突然変異 ステートメントが切り取られたり、貼り付けられたり、削除されたりするため、結果としてコードの一部行が削除される可能性があります。
  • 値の突然変異 – ループの境界や閾値を変更するなど、主要なパラメータや定数の値が変更されます。
  • 決定突然変異 – 制御文が変更されます。例えば、反転します。ping 関係演算子、または条件の否定。

ツールは演算子をこれら 3 つの見出しの下にグループ化するため、生存する変異体を生成したファミリーは、どのタイプのアサーションが欠落しているかをテスターに​​伝えます。生存する決定変異体は通常、テストされていないブランチを示し、それは以下と重複します。 ループテスト.

突然変異テストの自動化

ミューテーションテストは手動で実行すると非常に時間と手間がかかるため、自動化ツールを使用することをお勧めします。自動化ツールはコスト削減にもつながります。ミューテーションツールは、ミュータントをコンパイルし、実行スケジュールを設定し、失敗したテストごとにどのミュータントが停止されたかを記録し、スコアを報告します。

利用可能なツール一覧:

  • ストライカー — オープンソースの変異テストフレームワークで、 Javaスクリプトと TypeScript (StrykerJS)、C#および.NET (Stryker.NET)、Scala (Stryker4s)。
  • PITPITest とも表記される、突然変異検査システム Java そして、コンパイルされたバイトコードを変更し、MavenにプラグインするJVMと Gradle 一緒に構築する JUnit.

どちらもビルドステップとして実行されるため、同じ場所に属する 継続的インテグレーション パイプラインは残りの部分と同様に 自動化テスト 上。

突然変異スコア

突然変異スコアは、全突然変異体数に対する、死滅した突然変異体数の割合として定義される。

突然変異スコア = (殺された突然変異体 / 突然変異体の総数) * 100

以下に、ほとんどのツールが表示する形式で数式を示します。

突然変異スコアの計算式:殺された突然変異体の数を突然変異体の総数で割り、100を掛ける

テストケースは、スコアが100パーセントに達したときに変異が適切であると説明されます。実際には、分母は除外する必要があります。 同等の変異体 ―構文が変更されても元のものと全く同じように動作する変異体。そのため、どのテストでもそれらを排除することはできません。したがって、ツールは排除された変異体の数を、排除された変異体と生存している非同等の変異体の合計数で割った値を報告し、同等の変異体についてはテスターがフラグを立てるようにします。

実験結果から、突然変異テストはテストケースの妥当性を評価する効果的な方法であることが示されている。主な欠点は、突然変異体を生成し、それぞれの突然変異体に対してすべてのテストケースを実行するコストが高いことである。

突然変異検査 vs Code カバレッジ

ハイ テストカバレッジ これは強力なテストを証明するものではありません。行カバレッジと分岐カバレッジは、どのステートメントが実行されたかを記録するだけで、その後に何かが検証されたかどうかは記録しないため、メソッドを呼び出して何もアサートしないテストでもカバレッジされたとみなされます。ミューテーションテストはこのギャップを埋めます。なぜなら、ミュータントは実際にアサートが失敗した場合にのみ停止するからです。

側面 Code カバレッジ 変異スコア
測定対象 テストはどの行または分岐を実行したか テストで検出された注入された欠陥はどれだったのか
主張に敏感 いいえ、アサーションがゼロのテストでもカバレッジは向上します はい、どの主張も失敗しないときに突然変異体が生き残ります
ランニングの費用 計測機器を用いたテストラン1回 生き残った変異体1体につき1回のテスト実行、今のところは遅い
典型的な使用 コミットごとにクイックゲート 重要モジュールに対するより詳細な定期点検
故障モード 100%カバー、ただし実際の検証なし 決して殺されない同等の突然変異体

この2つの指標は相互補完的です。カバレッジは到達しなかったコードを示し、ミューテーションスコアは到達したもののチェックされなかったコードを示します。どちらも同じ情報を提供します。 欠陥管理プロセス以下のような対策と併せて 欠陥密度.

突然変異テストの利点

変異テストの利点は次のとおりです。

  • これは、ソースプログラムの高い網羅率を達成するための強力な手法である。
  • テストスイート自体をテストするが、他のテストスイートはテストスイート自体をテストしない。 ソフトウェアテスト技術 直接行います。
  • ミューテーションテストは、ソフトウェア開発者に優れたレベルのエラー検出機能を提供する。
  • この手法はソースコード内の曖昧さを明らかにし、通常の実行では決して検出できない欠陥を暴く能力を持っている。
  • 生き残った変異体は対処可能だ。それぞれが、ソフトウェアスイートが見逃した特定の行と特定の変更点を指摘している。
  • 顧客はこのテストによって、より信頼性が高く安定したシステムを利用できるようになるというメリットを享受できます。

突然変異テストの欠点

一方、突然変異検査には以下のような欠点があります。

  • 変異テストは、多数の変異プログラムを生成してコンパイルする必要があるため、非常にコストと時間がかかります。
  • 時間がかかるため、このテストは自動化ツールなしでは実施できないと言っても過言ではないでしょう。
  • 各変異体は、元のプログラムと同じ数のテストケースによって実行されるため、多数の変異体を用いてテストスイート全体を実行する必要がある。
  • 同等の変異体は、いかなる検査でも死滅させることができず、真の生存者と区別するには通常、手作業による確認が必要となる。
  • この方法はソースコードを変更するため、適用できません。 ブラック Box テスト.

突然変異検査はいつ行うべきか

上記のコストプロファイルから、ミューテーションテストはコードベース全体に対してコミットごとに実行されることは稀である。検出されない欠陥が大きな損失につながり、テスト対象のコードが小さく、かつ迅速に変化する可能性がある場合に、ミューテーションテストは費用対効果を発揮する。

  • 安全性が重要なロジックまたは財務ロジック ―支払い計算、税務規則、承認チェックなど、誤った回答を黙って見過ごすことは、事故よりも深刻な事態を招く。
  • 不審なほどカバー率の高いスイート ―カバー率がほぼ100%と表示されているにもかかわらず、欠陥が見過ごされている場合。
  • レガシーコードのリファクタリング ―突然変異の結果は、既存の検査で回帰を検出できるかどうかを明らかにする。
  • ライブラリと共有コンポーネント — 再利用された欠陥 コンポーネント 呼び出し元ごとに乗算されます。
  • 練習中のチーム テスト駆動開発 ―このスコアは、最初に作成されたテストが実際に機能しているかどうかを確認するものです。

使い捨てのプロトタイプ、薄い接着線や分岐ロジックのない生成コード、あるいは低速なコードが支配的なスイートで実行する価値は通常ありません。 統合テスト すでに1回の通過に数時間かかる作業だ。

そのため、ほとんどのチームは変更されたファイルのみに実行範囲を限定し、重要なモジュールにしきい値を設定し、より広範囲の 回帰試験 スイートは残りの ソフトウェアテストのライフサイクル.

よくあるご質問

同等の変異とは、構文は変更するものの動作は変更しない変更のことで、例えば到達しないループ境界を置き換える場合などがこれに該当します。このような変異はどのテストでも排除できないため、スコアを信頼する前にフラグを立てて除外する必要があります。

普遍的な数値はありません。チームは一般的に、決済やセキュリティロジックなどの重要なモジュールには高い閾値を設定し、それ以外の部分には低い閾値を設定します。パーセンテージを追い求めるよりも、リスクの高いコードに残っている変異体を一つ一つ確認する方が効果的です。

この手法は、以下の2つの前提に基づいている。1つ目は、プログラマーはほぼ正しいコードを書くため、実際の欠陥は小さいという前提。2つ目は、小さな欠陥を検出するテストは、それらから派生する複雑な欠陥も検出できるという前提である。

変異を現在のブランチで変更されたファイルに限定し、カバレッジデータを再利用して変異体に関連するテストのみを実行し、変異体を並列実行し、絶対値ではなくスコアの低下に基づいてビルドを失敗させる。

機械学習モデルは、どの変異体が生き残る可能性が高いかを予測して実行を絞り込み、レビューのために同等の可能性のある変異体を分類し、均一な演算子の交換ではなく、プロジェクト履歴で見られた欠陥に似た変異体を生成します。

はい、機械的な部分に関してはそうです。生存している変異体とテスト対象のメソッドが与えられると、Copilotは不足しているアサーションまたはエッジケーステストを作成します。ただし、レビュー担当者は、期待値が正しいか、現在の動作から単にコピーされたものではないかを確認する必要があります。

結果を監査します。テスト駆動開発ではコードを書く前にテストを作成しますが、それらのテストが十分な検証を行うという保証はありません。同じモジュールに対して定期的にミューテーションを実行することで、レッド・グリーンサイクルによって生成されたテストが、誤った回答に対して実際に失敗するかどうかを確認できます。

いいえ。フォールトインジェクションは実行環境を破壊し、 ファズテスト 不正な入力を与えてアプリケーションを評価する。ミューテーションテストではソースコードを変更し、テストスイートを評価するため、評価対象が異なる。