(57)【要約】【課題】テストケースが複数のステートメントを含む場合であっても、例外を発生させたミュータントとの対応づけを行うこと。【解決手段】処理部１ｂは、ミューテーション解析において、ミュータントの利用に応じて利用するミュータントを記憶部１ａに格納する。処理部１ｂは、テストケースの実行における例外の発生に応じ、当該例外に対応するスタックトレースより当該例外に関連するステートメントを特定する。記憶部１ａは、特定したステートメントとミュータントとを対応づけて記憶部１ａに格納する。【選択図】図１
2019128812.tif 000002
【特許請求の範囲】
【請求項１】
複数のステートメントを含むテストケースのミューテーション解析において発生した例外についての、ミュータントの識別プログラムであって、
前記ミューテーション解析において、前記ミュータントの利用に応じて利用する前記ミュータントを記憶し、
前記テストケースの実行における例外の発生に応じ、当該例外に対応するスタックトレースより当該例外に関連するステートメントを特定し、
前記ステートメントと前記ミュータントとを対応づけて記憶する、
処理をコンピュータに実行させる識別プログラム。
【請求項２】
前記スタックトレースに基づいて、複数の前記ミュータントのうち前記ミューテーション解析に用いる前記ミュータントを選択する、請求項１記載の識別プログラム。
【請求項３】
前記スタックトレースを参照して、発生した前記例外を前記ミュータントごとに特定し、発生した全ての前記例外を網羅する前記ミュータントの組のうち前記ミューテーション解析の実行コストが小さい組を優先的に選択する、請求項２記載の識別プログラム。
【請求項４】
前記ミュータントの数が最小の組を選択する、請求項３記載の識別プログラム。
【請求項５】
前記ミュータントの実行時間の和が最小の組を選択する、請求項３記載の識別プログラム。
【請求項６】
複数のステートメントを含むテストケースのミューテーション解析において発生した例外についての、ミュータントの識別装置であって、
記憶部と、
前記ミューテーション解析において、前記ミュータントの利用に応じて利用する前記ミュータントを前記記憶部に格納し、前記テストケースの実行における例外の発生に応じ、当該例外に対応するスタックトレースより当該例外に関連するステートメントを特定し、前記ステートメントと前記ミュータントとを対応づけて前記記憶部に格納する処理部と、
を有する識別装置。
【請求項７】
複数のステートメントを含むテストケースのミューテーション解析において発生した例外についての、ミュータントの識別方法であって、コンピュータが、
前記ミューテーション解析において、前記ミュータントの利用に応じて利用する前記ミュータントを記憶し、
前記テストケースの実行における例外の発生に応じ、当該例外に対応するスタックトレースより当該例外に関連するステートメントを特定し、
前記ステートメントと前記ミュータントとを対応づけて記憶する、
識別方法。
【発明の詳細な説明】
【技術分野】
【０００１】
本発明は識別プログラム、識別装置および識別方法に関する。
【背景技術】
【０００２】
ソフトウェア開発の現場では、ソフトウェアの品質向上を図るため、ソフトウェアのプログラムに対するテストが行われることがある。また、テスト自体の有効性が評価されることもある。テストの評価手法として、ミューテーション解析と呼ばれる手法が用いられることがある。
【０００３】
ミューテーション解析は、プログラム内の要素を意図的に変化させることでプログラムにバグを埋め込み、テストが該当のバグをどの程度検出できるかを調べる手法である。バグが埋め込まれたプログラムは、ミュータントと呼ばれることがある。ミューテーション解析では、複数のミュータントに所定の入力を与えたときの出力を確認することで、テストが各ミュータントを検出した割合（ミューテーションスコアと呼ばれることがある）によりテストの有効性を評価することがある。
【０００４】
また、原仕様に誤りを意図的に埋め込んだ誤り仕様を仮想的に実行し、原仕様の実行
結果と相違する結果を生ずるテストケースを、誤り検出に有効なテストケースであると予め判定するテストケース評価装置の提案がある。
【先行技術文献】
【特許文献】
【０００５】
【特許文献１】特開２０００−５７０１４号公報
【発明の概要】
【発明が解決しようとする課題】
【０００６】
従来のミューテーション解析技術においては、テストケースごとに、ミューテーションスコアを算出して、妥当性を判断していた。最適なミュータントを選択し、実行するミュータント数を削減することで、ミューテーション解析を高速化することが求められている。テストケースに含まれる複数のステートメントを、選択的に実行してミューテーション解析を高速化する場合、テストケースごとにミューテーションスコアを算出するだけでは、テストケースに含まれるステートメントごとの当否を判断することができなかった。
【０００７】
１つの側面では、本発明は、テストケースが複数のステートメントを含む場合であっても、例外を発生させたミュータントとの対応づけを行うことを目的とする。
【課題を解決するための手段】
【０００８】
１つの態様では、複数のステートメントを含むテストケースのミューテーション解析において発生した例外についての、ミュータントの識別プログラムが提供される。識別プログラムは、ミューテーション解析において、ミュータントの利用に応じて利用するミュータントを記憶し、テストケースの実行における例外の発生に応じ、当該例外に対応するスタックトレースより当該例外に関連するステートメントを特定し、ステートメントとミュータントとを対応づけて記憶する、処理をコンピュータに実行させる。
【発明の効果】
【０００９】
１つの側面では、テストケースが複数のステートメントを含む場合であっても、例外を発生させたミュータントとの対応づけを行うことができる。
【図面の簡単な説明】
【００１０】
【図１】第１の実施の形態の識別装置を示す図である。
【図２】ミュータント選択の例を示す図である。
【図３】第２の実施の形態の解析装置のハードウェア例を示す図である。
【図４】ミューテーション解析の例を示す図である。
【図５】ミューテーション解析の実行コストの例を示す図である。
【図６】ミュータント選択の例を示す図である。
【図７】テストケースベースのミュータント選択の例を示す図である。
【図８】テストケースベースのミュータント選択の問題点を示す図である。
【図９】解析装置の機能例を示す図である。
【図１０】ミュータント生成例を示す図である。
【図１１】テスト実行例を示す図である。
【図１２】例外・スタックトレースの集約例を示す図である。
【図１３】ミュータント選択の例を示す図である。
【図１４】集合被覆問題の例を示す図である。
【図１５】テスト対象プログラムの例を示す図である。
【図１６】テストコードの例を示す図である。
【図１７】全ミュータントテーブルの例を示す図である。
【図１８】例外テーブルの例を示す図である。
【図１９】関連テーブルの例を示す図である。
【図２０】実行時間テーブルの例を示す図である。
【図２１】選択済ミュータントテーブルの例を示す図である。
【図２２】ミュータント選択の結果レポートの出力例を示す図である。
【図２３】ミューテーション解析の結果レポートの出力例を示す図である。
【図２４】ミュータント選択例を示すフローチャートである。
【図２５】ミュータントに対する例外の例（その１）を示す図である。
【図２６】ミュータントに対する例外の例（その２）を示す図である。
【図２７】ミュータントに対する例外の例（その３）を示す図である。
【図２８】ミュータントに対する例外の例（その４）を示す図である。
【図２９】ミュータントに対する例外の例（その５）を示す図である。
【図３０】ミュータントに対する例外の例（その６）を示す図である。
【図３１】ミュータントに対する例外の例（その７）を示す図である。
【図３２】ミュータントに対する例外の例（その８）を示す図である。
【図３３】ミュータントに対する例外の例（その９）を示す図である。
【図３４】ミュータントに対する例外の例（その１０）を示す図である。
【図３５】ミュータントに対する例外の例（その１１）を示す図である。
【図３６】ミュータントに対する例外の例（その１２）を示す図である。
【図３７】ミュータントに対する例外の例（その１３）を示す図である。
【図３８】ミュータントに対する例外の例（その１４）を示す図である。
【図３９】ミュータントと例外との関連の例を示す図である。
【図４０】関連に基づくミュータント選択の例を示す図である。
【図４１】ミュータントの選択結果の例を示す図である。
【図４２】ミュータント選択の比較例を示す図である。
【図４３】ミュータント選択の比較例（続き）を示す図である。
【図４４】ミューテーション解析結果の比較例を示す図である。
【図４５】解析装置によるミューテーション解析結果の例を示す図である。
【発明を実施するための形態】
【００１１】
以下、本実施の形態について図面を参照して説明する。
［第１の実施の形態］
図１は、第１の実施の形態の識別装置を示す図である。識別装置１は、ソフトウェアのプログラムに対するテストを行う。また、識別装置１は、ミューテーション解析の手法によりテスト自体の評価も行う。識別装置１は、テストの評価結果をユーザ（ソフトウェアの開発者）に提供し、ユーザによるテストの改善を支援する。
【００１２】
識別装置１は、記憶部１ａおよび処理部１ｂを有する。
記憶部１ａは、ＲＡＭ（Random Access Memory）などの揮発性記憶装置でもよいし、ＨＤＤ（Hard Disk Drive）やフラッシュメモリなどの不揮発性記憶装置でもよい。処理部１ｂは、ＣＰＵ（Central Processing Unit）、ＤＳＰ（Digital Signal Processor）、ＡＳＩＣ（Application Specific Integrated Circuit）、ＦＰＧＡ（Field Programmable Gate Array）などを含み得る。処理部１ｂはプログラムを実行するプロセッサでもよい。プロセッサは、複数のプロセッサの集合（マルチプロセッサ）を含み得る。識別装置１は、「コンピュータ」と呼ばれてもよい。
【００１３】
記憶部１ａは、テスト対象プログラム２およびテストコード３を記憶する。テスト対象プログラム２およびテストコード３の記述には、任意のプログラミング言語を用いることができる。
【００１４】
テスト対象プログラム２は、テストの対象となるプログラムである。テスト対象プログラム２のソースファイル名は、例えば“ＳｔｒｉｎｇＵｔｉｌｓ．ｘｘｘ”である。テスト対象プログラム２は、戻り値の型がブーリアンであるｉｓＥｍｐｔｙメソッド（関数でもよい）を含む。ｉｓＥｍｐｔｙメソッドは、入力が“ｎｕｌｌ”または長さ０の文字列の場合に“ｔｒｕｅ”を返し、それら以外の場合に“ｆａｌｓｅ”を返す。
【００１５】
テストコード３は、テスト対象プログラム２のテストに用いられるプログラムである。テストコード３のソースファイル名は、例えば“Ｔｅｓｔ．ｘｘｘ”である。テストコード３のｔｅｓｔＩｓＥｍｐｔｙメソッドは、１つのテストケースに相当する。テストコード３は、テスト対象プログラム２に対する入力と、それに対して期待される戻り値を確認するためのステートメントを複数含む。ここで、ステートメントとは、プログラムにおける１つの手続き、または、命令を表す文である。以下では、ミューテーション解析に関係するステートメントに着目する。
【００１６】
例えば、テストコード３は、３行目〜６行目に相当する４つのステートメントを含む。第１のステートメント（３行目）は、ｉｓＥｍｐｔｙメソッドへの入力“ｎｕｌｌ”に対して戻り値が“ｔｒｕｅ”であることの確認を示す。第２のステートメント（４行目）は、ｉｓＥｍｐｔｙメソッドへの入力“”（入力なし）に対して戻り値が“ｔｒｕｅ”であることの確認を示す。第３のステートメント（５行目）は、ｉｓＥｍｐｔｙメソッドへの入力“  ”（１字分のスペース）に対して戻り値が“ｆａｌｓｅ”であることの確認を示す。第４のステートメント（６行目）は、ｉｓＥｍｐｔｙメソッドへの入力“ｆｏｏ”に対して戻り値が“ｆａｌｓｅ”であることの確認を示す。
【００１７】
処理部１ｂは、ミューテーション解析の手法を用いて、テストコード３によるテストの有効性を評価する。また、処理部１ｂは、開発者によるテストコード３のリファクタリングを支援する。
【００１８】
ミューテーション解析を行うために、処理部１ｂは、テスト対象プログラム２に基づいて、バグ（元のコードとは異なるコード）を埋め込んだミュータントＭ１，Ｍ２，Ｍ３，Ｍ４を生成し、記憶部１ａに格納する。例えば、ミュータントＭ１は、テスト対象プログラム２の２行目の“ｃｓ  ＝＝  ｎｕｌｌ”の記述を、“ｃｓ  ！＝  ｎｕｌｌ”に置換したものである。ミュータントＭ２は、テスト対象プログラム２の２行目の“ｃｓ  ＝＝  ｎｕｌｌ”の記述を、“ｆａｌｓｅ”に置換したものである。ミュータントＭ３は、テスト対象プログラム２の２行目の“ｃｓ．ｌｅｎｇｔｈ（）  ＝＝  ０”の記述を、“ｃｓ．ｌｅｎｇｔｈ（）  ！＝  ０”に置換したものである。ミュータントＭ４は、テスト対象プログラム２の２行目の“ｃｓ．ｌｅｎｇｔｈ（）  ＝＝  ０”の記述を、“ｆａｌｓｅ”に置換したものである。
【００１９】
処理部１ｂは、テストコード３によりミュータントＭ１，Ｍ２，Ｍ３，Ｍ４それぞれを実行することで、バグを含むミュータントＭ１，Ｍ２，Ｍ３，Ｍ４を検出できるか確認する。着目するミュータントの戻り値が期待値と異なり、例外が発生すれば当該ミュータントを検出できることになる。一方、着目するミュータントの戻り値が期待値と同じであり、例外が発生しなければ当該ミュータントを検出できないことになる。
【００２０】
処理部１ｂは、ミューテーション解析において、ミュータントの利用に応じて利用するミュータントを記憶部１ａに格納する。例えば、処理部１ｂは、テスト対象プログラム２からミュータントＭ１を生成し、テストコード３を用いてテストを行う。すると、処理部１ｂは、ミュータントＭ１の利用に応じて、当該ミュータントＭ１を記憶部１ａに格納する。
【００２１】
処理部１ｂは、ミュータントＭ１に関するテストケース（すなわち、テストコード３）の実行の結果、例外Ｅ１の発生を検出する。例えば、例外Ｅ１の例外クラス名は、“ＮｕｌｌＰｏｉｎｔｅｒＥｘｃｅｐｔｉｏｎ”である。例外が発生した場合、当該例外に対応するスタックトレースが記憶部１ａ（あるいは、所定の記憶装置）に出力される。
【００２２】
スタックトレースは、例外が発生するまでのメソッドの呼び出し順番を示す情報である。例えば、スタックトレースの１行目には、例外クラス名やエラーメッセージなどを示す情報が含まれる（エラーメッセージがないこともある）。また、スタックトレースの２行目以降の行には、メソッド名、ソースファイル名およびソースファイルの行番号などを示す情報が、メソッドの呼び出し元から呼び出し先に向かい、下から上に順番に出力される（図中、クラス名の図示を省略している）。このような出力例の場合、一番上（すなわち、スタックトレースの２行目）に出力されるメソッドが異常を検知して例外を生成したメソッドである。
【００２３】
処理部１ｂは、テストケースの実行における例外の発生に応じ、当該例外に対応するスタックトレースより当該例外に関連するステートメントを特定し、特定したステートメントとミュータントとを対応づけて記憶部１ａに格納する。
【００２４】
例えば、例外Ｅ１のスタックトレースによれば、ミュータントＭ１のｉｓＥｍｐｔｙメソッドが、テストコード３（ソースファイル名“Ｔｅｓｔ．ｘｘｘ”）のｔｅｓｔＩｓＥｍｐｔｙメソッドにより呼び出されて実行されることで、例外が発生している。なお、スタックトレース中のソースファイル名“ＳｔｒｉｎｇＵｔｉｌｓ．ｘｘｘ”は、当該例外時に実行されたミュータント（例外Ｅ１であれば、ミュータントＭ１）を示すものとする。
【００２５】
また、例外Ｅ１の発生要因となったテストコード３中のステートメントは、３行目のステートメントである（スタックトレースのうちの“Ｔｅｓｔ．ｘｘｘ：３”の“３”は行番号“３”を示す）。したがって、処理部１ｂは、例外Ｅ１に関連するテストコード３のステートメントが、テストコード３の３行目のステートメントと特定する。処理部１ｂは、特定したステートメントと、ミュータントＭ１とを対応づけて記憶部１ａに格納する。例えば、処理部１ｂは、ミュータントＭ１と例外Ｅ１のスタックトレースとの関連を示す情報を記憶部１ａに格納してもよい。
【００２６】
図１の例では、ミュータントＭ２，Ｍ３，Ｍ４のテスト実行においても例外が発生する。ミュータントＭ２の場合、例外Ｅ２が発生する。例外Ｅ２の例外クラス名は“ＮｕｌｌＰｏｉｎｔｅｒＥｘｃｅｐｔｉｏｎ”である。また、例外Ｅ２のスタックトレースによれば、例外Ｅ２に関連するテストコード３のステートメントは、３行目のステートメントである。処理部１ｂは、テストコード３の３行目のステートメントと、ミュータントＭ２とを対応づけて記憶部１ａに格納する。
【００２７】
ミュータントＭ３の場合、例外Ｅ３が発生する。例外Ｅ３の例外クラス名は“ＡｓｓｅｒｔｉｏｎＥｒｒｏｒ”である。また、例外Ｅ３のスタックトレースによれば、例外Ｅ３に関連するテストコード３のステートメントは、４行目のステートメントである。処理部１ｂは、テストコード３の４行目のステートメントと、ミュータントＭ３とを対応づけて記憶部１ａに格納する。
【００２８】
ミュータントＭ４の場合、例外Ｅ４が発生する。例外Ｅ４の例外クラス名は“ＡｓｓｅｒｔｉｏｎＥｒｒｏｒ”である。また、例外Ｅ４のスタックトレースによれば、例外Ｅ４に関連するテストコード３のステートメントは、４行目のステートメントである。処理部１ｂは、テストコード３の４行目のステートメントと、ミュータントＭ４とを対応づけて記憶部１ａに格納する。
【００２９】
このように、識別装置１によれば、複数のステートメントを含むテストケースのミューテーション解析において発生した例外についてのミュータントが識別される。識別装置１によれば、ミューテーション解析において、ミュータントの利用に応じて利用するミュータントが記憶される。そして、テストケースの実行における例外の発生に応じ、当該例外に対応するスタックトレースより当該例外に関連するステートメントが特定され、ステートメントとミュータントとが対応づけて記憶される。
【００３０】
これにより、テストケースが複数のステートメントを含む場合であっても、例外を発生させたミュータントとの対応づけを行うことができる。上記の例でいえば、処理部１ｂは、テストコード３で示されるテストケースの４つのステートメントに関して、例外Ｅ１，Ｅ２に関連する３行目のステートメントをミュータントＭ１，Ｍ２に対応づける。処理部１ｂは、例外Ｅ３，Ｅ４に関連する４行目のステートメントをミュータントＭ３，Ｍ４に対応づける。例えば、処理部１ｂは、テストケースのステートメントとミュータントの対応関係を表示装置により表示させ、開発者に提示することで、開発者によるテストコード３の改善を促せる。テストコード３の改善は、ソフトウェアの品質向上に寄与する。
【００３１】
また、処理部１ｂは、各ステートメントにおける例外の発生状況に応じて、冗長な例外を発生させるミュータントをミューテーション解析の利用対象から除外し、ミューテーション解析の高速化を図ることもできる。
【００３２】
図２は、ミュータント選択の例を示す図である。図２（Ａ）は、発生した例外の集約を示す。ここで、例外Ｅ１，Ｅ２は、スタックトレースの内容が同じであるとする。処理部１ｂは、例外Ｅ１，Ｅ２それぞれのスタックトレースを比較し、両スタックトレースの内容が同じであると判定すると、例外Ｅ１，Ｅ２を集約する。ここで、例えば、処理部１ｂは、２つのスタックトレースにおける例外クラス名と、例外を生成したメソッド（あるいは、例外を生成したメソッドの呼び出し元のメソッド）とが一致する場合に、両スタックトレースの内容が同じであると判定してもよい。処理部１ｂは、ミュータントＭ１に加えて、ミュータントＭ２も例外Ｅ１に関連づける。また、例外Ｅ３，Ｅ４は、スタックトレースの内容が同じであるとする。このため、処理部１ｂは、例外Ｅ３，Ｅ４を集約する。処理部１ｂは、ミュータントＭ３に加えて、ミュータントＭ４も例外Ｅ３に関連づける。
【００３３】
処理部１ｂは、集約後の全ての例外Ｅ１，Ｅ３をカバーできるように、ミュータントＭ１，Ｍ２，Ｍ３，Ｍ４の中からミューテーション解析に用いる最小限のミュータントを選択する。例えば、処理部１ｂは、ミュータントの選択を集合被覆問題に帰着させてソルバにより解くことで、集約後の全ての例外Ｅ１，Ｅ３をカバーするミュータントを選択する。集合被覆問題は、集合Ｕと集合Ｕの部分集合の集合Ｓとが与えられたとき、集合Ｕの要素を全てカバーするように集合Ｓから最小個数の部分集合を選ぶ最適化問題である。
【００３４】
図２（Ｂ）は、ミュータントの選択結果を示す。例えば、処理部１ｂは、共通の例外Ｅ１を発生させるミュータントＭ１，Ｍ２のうち、ミュータントＭ１を選択する。また、処理部１ｂは、共通の例外Ｅ３を発生させるミュータントＭ３，Ｍ４のうち、ミュータントＭ３を選択する。すなわち、処理部１ｂは、ミュータントＭ１に対して冗長な例外を発生させるミュータントＭ２をミューテーション解析の利用対象から除外する。また、処理部１ｂは、ミュータントＭ３に対して冗長な例外を発生させるミュータントＭ４をミューテーション解析の利用対象から除外する。こうして、発生する例外を網羅しつつ、ミューテーション解析に利用するミュータントを削減することができる。また、ミュータントを削減することで、ミューテーション解析の実行時間を短縮できる。
【００３５】
なお、処理部１ｂは、各ミュータントの実行時間を計測しておき、集約後の全ての例外Ｅ１，Ｅ３をカバーするミュータントの組のうち、当該組に属するミュータントの実行時間の和が最小になるミュータントの組を選択してもよい。これにより、ミューテーション解析の実行時間を更に短縮できる。
【００３６】
また、上記のように、発生した例外を基準にミュータント選択を行う他、テストケースのステートメントを基準にミュータント選択を行うことも考えられる。例えば、処理部１ｂは、テストケースの同じステートメントで例外を発生させた複数のミュータントを１つに絞り込んでもよい。より具体的には、処理部１ｂは、テストコード３（テストケース）の３行目のステートメントに関して例外Ｅ１，Ｅ２を発生させたミュータントＭ１，Ｍ２を、ミュータントＭ１に絞り込んでもよい。また、処理部１ｂは、テストコード３の４行目のステートメントに関して例外Ｅ３，Ｅ４を発生させたミュータントＭ３，Ｍ４を、ミュータントＭ３に絞り込んでもよい。
【００３７】
［第２の実施の形態］
図３は、第２の実施の形態の解析装置のハードウェア例を示す図である。解析装置１００は、ＣＰＵ１０１、ＲＡＭ１０２、ＨＤＤ１０３、画像信号処理部１０４、入力信号処理部１０５、媒体リーダ１０６および通信インタフェース１０７を有する。解析装置１００は、第１の実施の形態の識別装置１の一例である。ＣＰＵ１０１は、第１の実施の形態の処理部１ｂの一例である。ＲＡＭ１０２またはＨＤＤ１０３は、第１の実施の形態の記憶部１ａの一例である。
【００３８】
ＣＰＵ１０１は、プログラムの命令を実行するプロセッサである。ＣＰＵ１０１は、ＨＤＤ１０３に記憶されたプログラムやデータの少なくとも一部をＲＡＭ１０２にロードし、プログラムを実行する。なお、ＣＰＵ１０１は複数のプロセッサコアを含んでもよい。また、解析装置１００は複数のプロセッサを有してもよく、以下で説明する処理を複数のプロセッサまたはプロセッサコアを用いて並列に実行してもよい。また、複数のプロセッサの集合を「マルチプロセッサ」または単に「プロセッサ」と言うことがある。
【００３９】
ＲＡＭ１０２は、ＣＰＵ１０１が実行するプログラムやＣＰＵ１０１が演算に用いるデータを一時的に記憶する揮発性の半導体メモリである。なお、解析装置１００は、ＲＡＭ以外の種類のメモリを備えてもよく、複数個のメモリを備えてもよい。
【００４０】
ＨＤＤ１０３は、ＯＳ（Operating System）やミドルウェアやアプリケーションソフトウェアなどのソフトウェアのプログラム、および、データを記憶する不揮発性の記憶装置である。なお、解析装置１００は、フラッシュメモリやＳＳＤ（Solid State Drive）などの他の種類の記憶装置を備えてもよく、複数の不揮発性の記憶装置を備えてもよい。
【００４１】
画像信号処理部１０４は、ＣＰＵ１０１からの命令に従って、解析装置１００に接続されたディスプレイ１１に画像を出力する。ディスプレイ１１としては、ＣＲＴ（Cathode Ray Tube）ディスプレイ、液晶ディスプレイ（ＬＣＤ：Liquid Crystal Display）、プラズマディスプレイ、有機ＥＬ（ＯＥＬ：Organic Electro-Luminescence）ディスプレイなど、任意の種類のディスプレイを用いることができる。
【００４２】
入力信号処理部１０５は、解析装置１００に接続された入力デバイス１２から入力信号を取得し、ＣＰＵ１０１に出力する。入力デバイス１２としては、マウス・タッチパネル・タッチパッド・トラックボールなどのポインティングデバイス、キーボード、リモートコントローラ、ボタンスイッチなどを用いることができる。また、解析装置１００に、複数の種類の入力デバイスが接続されていてもよい。
【００４３】
媒体リーダ１０６は、記録媒体１３に記録されたプログラムやデータを読み取る読み取り装置である。記録媒体１３として、例えば、磁気ディスク、光ディスク、光磁気ディスク（ＭＯ：Magneto-Optical disk）、半導体メモリなどを使用できる。磁気ディスクには、フレキシブルディスク（ＦＤ：Flexible Disk）やＨＤＤが含まれる。光ディスクには、ＣＤ（Compact Disc）やＤＶＤ（Digital Versatile Disc）が含まれる。
【００４４】
媒体リーダ１０６は、例えば、記録媒体１３から読み取ったプログラムやデータを、ＲＡＭ１０２やＨＤＤ１０３などの他の記録媒体にコピーする。読み取られたプログラムは、例えば、ＣＰＵ１０１によって実行される。なお、記録媒体１３は可搬型記録媒体であってもよく、プログラムやデータの配布に用いられることがある。また、記録媒体１３やＨＤＤ１０３を、コンピュータ読み取り可能な記録媒体と言うことがある。
【００４５】
通信インタフェース１０７は、ネットワーク１４に接続され、ネットワーク１４を介して他の装置と通信を行うインタフェースである。通信インタフェース１０７は、例えば、スイッチやルータなどの通信装置とケーブルで接続される。
【００４６】
図４は、ミューテーション解析の例を示す図である。ここでは、テスト対象のプログラム２０を用いて、解析装置１００によるミューテーション解析を例示する。プログラム２０は、関数ａｂｓの記述を含む。ここで、ミューテーション解析とは、プログラムの１要素を変化させることでバグを埋め込み、テストが埋め込んだバグをどれだけ検出できるかを調べる手法である。バグが埋め込まれたプログラムは「ミュータント」と呼ばれる。ミュータントは、例えば、（ミューテーション箇所，ミューテーション内容）の組（ミューテーション記述子）で表される。
【００４７】
具体的には、プログラム２１は、プログラム２０の２行目に含まれる“＜＝”の記述を、“＞”に変化させたミュータントである。プログラム２１の識別名は“ｍｕｔａｎｔ１”である。
【００４８】
また、プログラム２２は、プログラム２０の２行目に含まれる“０”の記述を、“１”に変化させたミュータントである。プログラム２２の識別名は“ｍｕｔａｎｔ２”である。
【００４９】
更に、プログラム２３は、プログラム２０の３行目に含まれる“−”の記述を、“−−”に変化させたミュータントである。プログラム２３の識別名は“ｍｕｔａｎｔ３”である。
【００５０】
図４の例では、２つのテストケースを考える。第１のテストケース（Ｔｅｓｔｃａｓｅ１）は、ａｂｓ（２）＝＝２である。すなわち、第１のテストケースは、関数ａｂｓにｘ＝２を入力したとき、出力が“２”になるか否かを確認する。ａｂｓ（２）＝＝２が成立すれば“ｐａｓｓ”、成立しなければ“ｆａｉｌ”である。
【００５１】
第２のテストケース（Ｔｅｓｔｃａｓｅ２）は、ａｂｓ（−２）＝＝２である。すなわち、第２のテストケースは、関数ａｂｓにｘ＝−２を入力したとき、出力が“２”になるか否かを確認する。ａｂｓ（−２）＝＝２が成立すれば“ｐａｓｓ”、成立しなければ“ｆａｉｌ”である。
【００５２】
プログラム２１では、第１，第２のテストケースの何れも実行結果は“ｆａｉｌ”である。プログラム２２では、第１のテストケースの実行結果は“ｐａｓｓ”、第２のテストケースの実行結果は“ｐａｓｓ”である。プログラム２３では、第１のテストケースの実行結果は“ｐａｓｓ”、第２のテストケースの実行結果は“ｆａｉｌ”である。
【００５３】
この場合、第１のテストケースおよび第２のテストケースにより、プログラム２１に埋め込まれたバグを検出できることになる。したがって、プログラム２１に対するテスト結果は“ｋｉｌｌｅｄ”である。
【００５４】
また、第１のテストケースおよび第２のテストケースでは、プログラム２２に埋め込まれたバグを検出できないことになる。したがって、プログラム２２に対するテスト結果は“ｕｎｋｉｌｌｅｄ”である。
【００５５】
更に、第２のテストケースにより、プログラム２３に埋め込まれたバグを検出できることになる。したがって、プログラム２３に対するテスト結果は“ｋｉｌｌｅｄ”である。
例えば、解析装置１００は、検出されたバグの割合（ミューテーションスコア（mutation score））を算出し出力する。この場合、ミューテーションスコアは、２／３＝０．６６７である。ユーザ（例えば、ソフトウェアの開発者）は、ミューテーションスコアを向上させるようにテストケースを改善することで、テストの信頼性を向上させることができる。
【００５６】
図５は、ミューテーション解析の実行コストの例を示す図である。ここで、ミューテーション解析のために、ソースコード３０（または、ソースコードを所定のコード形式に変換した中間コード）からミュータント３１，３２，・・・，３３が生成される。
【００５７】
ミューテーション解析は、ミュータント３１，３２，・・・，３３それぞれをコンパイルしてオブジェクトコード３１ａ，３２ａ，・・・，３３ａを生成する処理やオブジェクトコード３１ａ，３２ａ，・・・，３３ａをテスト実行する処理を含む。コンパイルやテスト実行に要する時間を考慮すると、複数のミュータントに対するミューテーション解析の合計時間は次の式で表される。
【００５８】
合計時間＝（ミュータント数）＊（ミューテーション時間＋コンパイル時間）＋（ミュータント数）＊（テストケース数）＊（テストケース１つ当たりの平均実行時間）
したがって、ミューテーション解析は、利用するミュータントの数が多いほど時間がかかる。
【００５９】
図６は、ミュータント選択の例を示す図である。ミューテーション解析に利用するミュータントを削減することで、減らしたミュータントの分、ミューテーション解析の実行時間を短縮することができる。このとき、ミュータントの絞り込み後も、絞り込み前と同じ能力をもつミュータントの集合を選ぶことが好ましい。例えば、ミュータントを削減し過ぎてしまうと、ミューテーション解析による評価結果（ミューテーションスコア）の精度が低下するおそれがあるためである。
【００６０】
図７は、テストケースベースのミュータント選択の例を示す図である。ミュータント選択の方法として、同じテストケースでｋｉｌｌできるミュータントを冗長とみなして、冗長なミュータント以外のミュータントを選択することが考えられる。ここで、テスト対象プログラム４０は、テスト対象のプログラムである。テスト対象プログラム４０は、入力された大文字のアルファベットの文字コードを、小文字のアルファベットの文字コードに変換して（大文字のアルファベットの文字コードをスペースの文字コード分シフトして）出力する関数ｔｏｌｏｗｅｒを含む。関数ｔｏｌｏｗｅｒは、小文字のアルファベットやアルファベット以外が入力された場合には、入力値をそのまま出力する。テスト対象プログラム４０から、例えば、ミュータントｍ１，ｍ２，ｍ３，ｍ４，ｍ５，ｍ６，ｍ７が生成される。
【００６１】
ミュータントｍ１は、テスト対象プログラム４０の２行目の“＆＆”を、“｜｜”に置換したものである。ミュータントｍ２は、テスト対象プログラム４０の２行目の“＞＝”を、“＝＝”に置換したものである。ミュータントｍ３は、テスト対象プログラム４０の３行目の“＜＝”を、“＜”に置換したものである。ミュータントｍ４は、テスト対象プログラム４０の３行目の“＜＝”を、“＝＝”に置換したものである。ミュータントｍ５は、テスト対象プログラム４０の２行目の“＞＝”を、“＞”に置換したものである。ミュータントｍ６は、テスト対象プログラム４０の４行目の“＋”を、“−”に置換したものである。ミュータントｍ７は、テスト対象プログラム４０の４行目の“‘  ’”（１文字分のスペース）を、“０”に置換したものである。
【００６２】
テスト表４１は、テスト対象プログラム４０に対するテストケースと、テストケースで検出されるミュータントとを例示する。テスト表４１は、ＩＤ（IDentifier）、Ｉｎｐｕｔ、Ｅｘｐｅｃｔｅｄ  ｏｕｔｐｕｔ、および、ｄｅｔｅｃｔｅｄ  ｍｕｔａｎｔｓの項目を含む。ＩＤは、テストケースを識別する識別子である。Ｉｎｐｕｔは、ミュータントに対する入力である。Ｅｘｐｅｃｔｅｄ  ｏｕｔｐｕｔは、入力に対する出力の期待値である。ｄｅｔｅｃｔｅｄ  ｍｕｔａｎｔｓは、該当のテストケースにより検出されるミュータントの識別子である。
【００６３】
例えば、ＩＤ“ｔ１”のテストケースの入力は“Ａ”であり、出力の期待値は“ａ”である。ＩＤ“ｔ１”のテストケースに対して、ミュータントｍ４，ｍ５，ｍ６，ｍ７が検出される。
【００６４】
ＩＤ“ｔ２”のテストケースの入力は“Ｚ”であり、出力の期待値は“ｚ”である。ＩＤ“ｔ２”のテストケースに対してミュータントｍ２，ｍ３，ｍ６，ｍ７が検出される。
ＩＤ“ｔ３”のテストケースの入力は“ａ”であり、出力の期待値は“ａ”である。ＩＤ“ｔ３”のテストケースに対してミュータントｍ１が検出される。
【００６５】
ＩＤ“ｔ４”のテストケースの入力は“＠”であり、出力の期待値は“＠”である。ＩＤ“ｔ４”のテストケースに対して、ミュータントｍ１が検出される。
ＩＤ“ｔ５”のテストケースの入力は“￥ｎ”（改行コード）であり、出力の期待値は“￥ｎ”である。ＩＤ“ｔ５”のテストケースに対してミュータントｍ１が検出される。
【００６６】
この場合、ミュータントｍ２，ｍ３は、両方ともＩＤ“ｔ２”のテストケースでｋｉｌｌできるので冗長である。また、ミュータントｍ４，ｍ５は、両方ともＩＤ“ｔ１”のテストケースでｋｉｌｌできるので冗長である。更に、ミュータントｍ６，ｍ７は、両方ともＩＤ“ｔ１”のテストケースおよびＩＤ“ｔ２”のテストケースでｋｉｌｌできるので冗長である。
【００６７】
図８は、テストケースベースのミュータント選択の問題点を示す図である。入力および出力の期待値の組を含む複数のステートメントを１つのテストケースとして記述することがある。例えば、テストコード５０は、図７のテスト表４１における関数ｔｏｌｏｗｅｒのテストが１つのテストケースとして記述されたプログラムである。テストコード５０の２行目〜６行目の各ステートメントが、それぞれテスト表４１におけるＩＤ“ｔ１”〜“ｔ５”のテストケースに相当する。この場合、ミュータントｍ１，ｍ２，ｍ３，ｍ４，ｍ５は、１つのテストケースにより全てｋｉｌｌできる。したがって、ミュータントｍ１，ｍ２，ｍ３，ｍ４，ｍ５のうちの１つのミュータント以外のミュータントは冗長とみなされてしまう。ところが、１つのテストケースで複数のミュータントがｋｉｌｌされる場合、ｋｉｌｌされる要因は単一ではないことがある。テストケースベースのミュータント選択では、同じテストケースでｋｉｌｌできるものは同じ１つの要因によるものであると捉え、ミュータントを過剰に削減する可能性がある。
【００６８】
そこで、解析装置１００は、各ミュータントがｋｉｌｌされるときに発生する例外と当該例外のスタックトレースを重複がないようにまとめ、発生した例外を全てカバーするミュータントを選択することで、ミュータントを適切に絞り込む機能を提供する。
【００６９】
図９は、解析装置の機能例を示す図である。解析装置１００は、全ミュータント記憶部１１０、例外記憶部１２０、関連情報記憶部１３０、実行時間記憶部１４０、選択済ミュータント記憶部１５０、ミュータント生成部１６０、テスト実行部１７０、ミュータント選択部１８０および結果出力部１９０を有する。
【００７０】
全ミュータント記憶部１１０、例外記憶部１２０、関連情報記憶部１３０、実行時間記憶部１４０および選択済ミュータント記憶部１５０は、ＲＡＭ１０２またはＨＤＤ１０３に確保された記憶領域により実現される。ミュータント生成部１６０、テスト実行部１７０、ミュータント選択部１８０および結果出力部１９０は、ＣＰＵ１０１がＲＡＭ１０２に記憶されたプログラムを実行することで実現される。
【００７１】
全ミュータント記憶部１１０は、テスト対象プログラム６０に対してミュータント生成部１６０により生成された全てのミュータントを記憶する。
例外記憶部１２０は、テストコード８０によりミュータントをテスト実行した際に発生した例外に対応するスタックトレースを記憶する。スタックトレースは、例外が発生するまでのメソッドや関数の呼び出し順番を示す情報である。スタックトレースの出力機能は、例えば、使用するプログラミング言語の実行環境により提供される。スタックトレースには、該当のメソッドや関数が記述されたソースファイル名およびソースファイルの行番号の情報が含まれる。ソースファイルの行番号は、該当のソースファイルにおけるステートメントを示す。
【００７２】
関連情報記憶部１３０は、ミュータントと例外（スタックトレース）との関連を示す関連情報を記憶する。スタックトレースは、例外に関係するメソッドや関数が記述されたソースファイル名およびソースファイルの行番号を含むので、関連情報は、ミュータントとテストコード８０のステートメントとを対応づける情報であるともいえる。
【００７３】
実行時間記憶部１４０は、ミュータントのテスト実行に要した時間を、ミュータントごとに記憶する。
選択済ミュータント記憶部１５０は、ミューテーション解析のための利用対象としてミュータント選択部１８０により選択されたミュータントを記憶する。
【００７４】
ミュータント生成部１６０は、テスト対象プログラム６０に入力を受け付ける。テスト対象プログラム６０は、例えば、ユーザにより作成される。ミュータント生成部１６０は、テスト対象プログラム６０のコードを部分的に別のコード（バグ）に置換したプログラム（ミュータント）を複数生成し、生成したミュータントを全ミュータント記憶部１１０に格納する。ミュータント生成部１６０は、例えば、所定のルール（ある演算や値を別の演算や別の値に変更するなど）に従って、テスト対象プログラム６０からミュータントを生成する。
【００７５】
なお、ミュータントのコンパイルを行う場合、ミュータント生成部１６０は、ミュータントのコンパイルを行う。ミュータント生成部１６０は、コンパイルにより生成されたミュータントごとのオブジェクトコードを全ミュータント記憶部１１０に格納する。この場合、ミュータントに対するテスト実行は、当該ミュータントのオブジェクトコードを用いて行われる。
【００７６】
テスト実行部１７０は、テストコード８０の入力を受け付ける。テストコード８０は、例えば、ユーザにより作成される。テスト対象プログラム６０およびテストコード８０それぞれの作成者は異なってもよい。テスト実行部１７０は、全ミュータント記憶部１１０に記憶された各ミュータントをテストコード８０（あるいは、テストコード８０をコンパイルして作成されたオブジェクトコード）によりテスト実行することで、テストコード８０の有効性を評価する。ただし、テスト実行部１７０は、ミュータント選択部１８０によるミュータント選択のために次の情報を取得する。ミュータント選択を行わない場合（選択済のミュータントを用いてテスト実行を行う場合）、次の情報を取得しなくてもよい。
【００７７】
テスト実行部１７０は、テスト実行により発生した例外に対応するスタックトレースを、例外記憶部１２０に格納する。また、テスト実行部１７０は、ミュータントと、当該ミュータントのテスト実行により発生した例外とを関連づけた関連情報を関連情報記憶部１３０に格納する。更に、テスト実行部１７０は、ミュータントのテスト実行に要した時間（実行時間）を、ミュータントごとに実行時間記憶部１４０に格納する。
【００７８】
ミュータント選択部１８０は、テスト対象プログラム６０に対する全てのミュータントのうち、今後のミューテーション解析に利用するミュータントを選択する。すなわち、ミュータント選択部１８０は、ミューテーション解析に利用するミュータントの絞り込みを行う。ミュータント選択部１８０は、選択したミュータントを選択済ミュータント記憶部１５０に格納する。
【００７９】
結果出力部１９０は、選択済ミュータント記憶部１５０に記憶されたミュータントの情報に基づいて、結果レポート９０を出力する。結果レポート９０は、ミュータントの選択結果を示す情報である。
【００８０】
次に、ミュータント生成部１６０、テスト実行部１７０およびミュータント選択部１８０による処理を例示する。
図１０は、ミュータント生成例を示す図である。プログラム言語としてＪＡＶＡ（登録商標）を想定するが、他のプログラミング言語でもよい。テスト対象プログラム６０ａは、テスト対象プログラム６０の一例である。テスト対象プログラム６０ａは、入力が“ｎｕｌｌ”または長さ０の文字列のときに“ｔｒｕｅ”を返し、それら以外のときに“ｆａｌｓｅ”を返すｉｓＥｍｐｔｙメソッドを含む。テスト対象プログラム６０ａのファイル名は、“ＳｔｒｉｎｇＵｔｉｌｓ．ｊａｖａ”である。例えば、ミュータント生成部１６０は、テスト対象プログラム６０ａに基づいて、ミュータントＭＴ１，ＭＴ２，ＭＴ３，ＭＴ４を生成する。
【００８１】
ミュータントＭＴ１は、テスト対象プログラム６０ａの２行目の“ｃｓ  ＝＝  ｎｕｌｌ”の記述を、“ｃｓ  ！＝  ｎｕｌｌ”に置換したものである。ミュータントＭＴ２は、テスト対象プログラム６０ａの２行目の“ｃｓ  ＝＝  ｎｕｌｌ”の記述を、“ｆａｌｓｅ”に置換したものである。ミュータントＭＴ３は、テスト対象プログラム６０ａの２行目の“ｃｓ．ｌｅｎｇｔｈ（）  ＝＝  ０”の記述を、“ｃｓ．ｌｅｎｇｔｈ（）  ！＝  ０”に置換したものである。ミュータントＭＴ４は、テスト対象プログラム６０ａの２行目の“ｃｓ．ｌｅｎｇｔｈ（）  ＝＝  ０”の記述を、“ｆａｌｓｅ”に置換したものである。
【００８２】
また、テストコード８０ａは、ｉｓＥｍｐｔｙメソッドに対する入力に応じたｉｓＥｍｐｔｙメソッドの出力を確認するｔｅｓｔＩｓＥｍｐｔｙメソッドを含む。テストコード８０ａのファイル名は、“ＵｔｉｌｓＴｅｓｔ．ｊａｖａ”である。テストコード８０ａは、テストコード８０の一例である。
【００８３】
例えば、テストコード８０ａの３行目のステートメントは、ｉｓＥｍｐｔｙメソッドに“ｎｕｌｌ”を入力したときの戻り値が“ｔｒｕｅ”であることを確認する。戻り値が“ｔｒｕｅ”であれば正常（ｐａｓｓ）である。戻り値が“ｆａｌｓｅ”であれば異常（ｆａｉｌ、例外発生）である。
【００８４】
テストコード８０ａの４行目のステートメントは、ｉｓＥｍｐｔｙメソッドに“”（入力なし）を入力したときの戻り値が“ｔｒｕｅ”であることを確認する。テストコード８０ａの５行目のステートメントは、ｉｓＥｍｐｔｙメソッドに“  ”（１文字分のスペース）を入力したときの戻り値が“ｆａｌｓｅ”であることを確認する。テストコード８０ａの６行目のステートメントは、ｉｓＥｍｐｔｙメソッドに“ｆｏｏ”を入力したときの戻り値が“ｆａｌｓｅ”であることを確認する。
【００８５】
図１１は、テスト実行例を示す図である。テスト実行部１７０は、テストコード８０ａを実行し、ミュータントＭＴ１，ＭＴ２，ＭＴ３，ＭＴ４それぞれのテストを行う。ここで、テストコード８０ａにおけるｉｓＥｍｐｔｙメソッドの呼び出し先は、テスト実行の対象となっているミュータントに含まれるｉｓＥｍｐｔｙメソッドである。
【００８６】
この場合、ミュータントＭＴ１，ＭＴ２，ＭＴ３，ＭＴ４それぞれについて例外が発生する。テスト実行部１７０は、発生した例外に対応するスタックトレースを取得し、例外記憶部１２０に格納する。前述のように、スタックトレースには、例外の内容が記録されている。スタックトレースは、例えば、例外クラス名、例外発生に至るまでのメソッドの呼び出しの過程、当該メソッドが含まれるソースファイル名および該当のソースファイル内の該当のメソッドが記述されている行番号などの情報を含む。
【００８７】
例えば、ミュータントＭＴ１に対して例外ＥＸ１が発生する。例外ＥＸ１のスタックトレースには、例外クラス名“ＮｕｌｌＰｏｉｎｔｅｒＥｘｃｅｐｔｉｏｎ”や例外に関係するミュータントＭＴ１やテストコード８０ａのソースファイル名、メソッド名、ソースファイル中の該当のメソッドが記述された行番号などが含まれる。また、ミュータントＭＴ２に対しては、例外ＥＸ２が発生する。ミュータントＭＴ３に対しては、例外ＥＸ３が発生する。ミュータントＭＴ４に対しては、例外ＥＸ４が発生する。
【００８８】
図１２は、例外・スタックトレースの集約例を示す図である。前述の例外ＥＸ１，ＥＸ２のスタックトレースは、同一の内容であるとする。この場合、テスト実行部１７０は、例外ＥＸ１，ＥＸ２を例外ＥＸ１に集約し、ミュータントＭＴ１，ＭＴ２をそれぞれ例外ＥＸ１に関連づけた関連情報を関連情報記憶部１３０に格納する。
【００８９】
また、例外ＥＸ３，ＥＸ４のスタックトレースは、同一の内容であるとする。この場合、テスト実行部１７０は、例外ＥＸ３，ＥＸ４を例外ＥＸ３に集約し、ミュータントＭＴ３，ＭＴ４をそれぞれ例外ＥＸ３に関連づけた関連情報を関連情報記憶部１３０に格納する。
【００９０】
図１３は、ミュータント選択の例を示す図である。ミュータント選択部１８０は、集約後の全ての例外ＥＸ１，ＥＸ３をカバーできるように、ミュータントＭ１，Ｍ２，Ｍ３，Ｍ４の中からミューテーション解析に用いる最小限のミュータントを選択する。集合被覆問題は、集合Ｕと集合Ｕの部分集合の集合Ｓとが与えられたとき、集合Ｕの要素を全てカバーするように集合Ｓから最小個数の部分集合を選ぶ最適化問題である。
【００９１】
図１３では、ミュータントＭＴ１，ＭＴ３が選択された場合を例示している。ミュータントＭＴ２，ＭＴ４は、ミューテーション解析の利用対象から除外されたことになる。
ここで、集合被覆問題について説明する。
【００９２】
図１４は、集合被覆問題の例を示す図である。一例として、集合Ｕ＝｛１，２，３，４，５｝、集合Ｓ＝｛｛１，２，３｝，｛２，４｝，｛３，４｝，｛４，５｝｝の場合を考える。この場合、集合Ｕの要素を全てカバーするように集合Ｓから最小個数の部分集合を選んだ解（最適解）Ｓｏｐｔは、Ｓｏｐｔ＝｛｛１，２，３｝，｛４，５｝｝である。ミュータント選択部１８０は、図１３で説明したミュータントの選択を、集合被覆問題に帰着させてソルバにより解くことで、集約後の全ての例外ＥＸ１，ＥＸ３をカバーする最小数のミュータントを選択する。ミュータント選択部１８０は、テスト実行部１７０により計測されたミュータントごとのテストの実行時間により各ミュータントを重み付けすることで、より実行時間の少ないミュータントの組み合わせを選択することもできる。
【００９３】
次に、解析装置１００の各部を更に詳細に説明する。以下の説明では、特に断らない限り、具体的なプログラムとして、図１０〜図１３で例示したテスト対象プログラム６０ａおよびテストコード８０ａに代えて、テスト対象プログラム６０およびテストコード８０を例示する。
【００９４】
図１５は、テスト対象プログラムの例を示す図である。テスト対象プログラム６０のファイル名は、“ＳｔｒｉｎｇＵｔｉｌｓ．ｊａｖａ”である。テスト対象プログラム６０は、文字列ｓｔｒと、整数ｌｅｎとの入力を受け付け、所定の戻り値を返すｌｅｆｔメソッドを含む。文字列ｓｔｒが“ｎｕｌｌ”であればｌｅｆｔメソッドの戻り値は“ｎｕｌｌ”である。整数ｌｅｎが、０よりも小さければ、ｌｅｆｔメソッドの戻り値は“ＥＭＰＴＹ”である。文字列ｓｔｒの長さが整数ｌｅｎ以下の長さであれば、ｌｅｆｔメソッドの戻り値は、文字列ｓｔｒである。これらの何れにも該当しなければ、ｌｅｆｔメソッドの戻り値は、文字列ｓｔｒの左端の文字を１番目とし、右側へ順に整数ｌｅｎ番目までの文字を抽出して得られる文字列である。
【００９５】
図１６は、テストコードの例を示す図である。テストコード８０のファイル名は、“ＳｔｒｉｎｇＵｔｉｌｓＴｅｓｔ．ｊａｖａ”である。テストコード８０は、テスト対象プログラム６０のｌｅｆｔメソッドに関するテストを行うｔｅｓｔＬｅｆｔ＿ｎｕｌｌメソッド、ｔｅｓｔＬｅｆｔ＿ｅｍｐｔｙメソッドおよびｔｅｓｔＬｅｆｔ＿ｖａｌｉｄメソッドを含む。これらの各メソッドは、ｌｅｆｔメソッドに対する確認内容を示す複数のステートメントを含む。
【００９６】
ｔｅｓｔＬｅｆｔ＿ｎｕｌｌメソッドは、テストコード８０の２〜４行目に相当する３つのステートメントを含む。２行目のステートメントは、（ｓｔｒ，ｌｅｎ）＝（ｎｕｌｌ，−１）を入力したときにｌｅｆｔメソッドの戻り値が“ｎｕｌｌ”であることを確認する。３行目のステートメントは、（ｓｔｒ，ｌｅｎ）＝（ｎｕｌｌ，０）を入力したときにｌｅｆｔメソッドの戻り値が“ｎｕｌｌ”であることを確認する。４行目のステートメントは、（ｓｔｒ，ｌｅｎ）＝（ｎｕｌｌ，２）を入力したときにｌｅｆｔメソッドの戻り値が“ｎｕｌｌ”であることを確認する。
【００９７】
ｔｅｓｔＬｅｆｔ＿ｅｍｐｔｙメソッドは、テストコード８０の７〜９行目に相当する３つのステートメントを含む。７行目のステートメントは、（ｓｔｒ，ｌｅｎ）＝（“”，−１）を入力したときにｌｅｆｔメソッドの戻り値が“”であることを確認する。８行目のステートメントは、（ｓｔｒ，ｌｅｎ）＝（“”，０）を入力したときにｌｅｆｔメソッドの戻り値が“”であることを確認する。９行目のステートメントは、（ｓｔｒ，ｌｅｎ）＝（“”，２）を入力したときにｌｅｆｔメソッドの戻り値が“”であることを確認する。
【００９８】
ｔｅｓｔＬｅｆｔ＿ｖａｌｉｄメソッドは、テストコード８０の１２〜１５行目に相当する４つのステートメントを含む。１２行目のステートメントは、（ｓｔｒ，ｌｅｎ）＝（ＦＯＯＢＡＲ，−１）を入力したときにｌｅｆｔメソッドの戻り値が“”であることを確認する。１３行目のステートメントは、（ｓｔｒ，ｌｅｎ）＝（ＦＯＯＢＡＲ，０）を入力したときにｌｅｆｔメソッドの戻り値が“”であることを確認する。１４行目のステートメントは、（ｓｔｒ，ｌｅｎ）＝（ＦＯＯＢＡＲ，３）を入力したときにｌｅｆｔメソッドの戻り値が“ＦＯＯ”であることを確認する。１５行目のステートメントは、（ｓｔｒ，ｌｅｎ）＝（ＦＯＯＢＡＲ，８０）を入力したときにｌｅｆｔメソッドの戻り値が“ＦＯＯＢＡＲ”であることを確認する。
【００９９】
図１７は、全ミュータントテーブルの例を示す図である。全ミュータントテーブル１１１は、ミュータント生成部１６０により生成され、全ミュータント記憶部１１０に格納される。全ミュータントテーブル１１１は、ミュータントの識別情報（ミュータントＩＤ）およびミューテーション記述子の項目を含む。ミュータントＩＤの項目には、ミュータントＩＤが登録される。ミューテーション記述子の項目には、ミューテーション記述子が登録される。
【０１００】
例えば、全ミュータントテーブル１１１には、ミュータントＩＤが“Ｍ１”、ミューテーション記述子が“２行目：“＝＝”−＞“！＝””というレコードが登録されている（“−＞”は右矢印記号を表す）。このレコードは、ミュータントＩＤ“Ｍ１”のミュータントは、テスト対象プログラム６０の２行目の“＝＝”を、“！＝”に置換したミュータントであることを示す。ここで、以下の説明では、ミュータントＩＤ“Ｍ１”のミュータントを、ミュータントＭ１のように表記する。
【０１０１】
全ミュータントテーブル１１１には、テスト対象プログラム６０に対してミュータント生成部１６０により生成される全てのミュータントを示すレコードが登録される。
図１８は、例外テーブルの例を示す図である。例外テーブル１２１は、例外記憶部１２０に格納される。例外テーブル１２１は、例外ＩＤおよび例外とスタックトレースの項目を含む。例外ＩＤの項目には、例外の識別情報（例外ＩＤ）が登録される。例外とスタックトレースの項目には、例外クラス名やスタックトレースの内容が登録される。
【０１０２】
例えば、例外テーブル１２１には、例外ＩＤ“Ｅ１”に対応する例外とスタックトレースが次の内容であることを示すレコードを含む。
（１行目）ｊａｖａ．ｌａｎｇ．ＡｓｓｅｒｔｉｏｎＥｒｒｏｒ：  ｅｘｐｅｃｔｅｄ  ｓａｍｅ：＜ｎｕｌｌ＞  ｗａｓ  ｎｏｔ：＜＞
（２行目）  ａｔ  ＳｔｒｉｎｇＵｔｉｌｓＴｅｓｔ．ｔｅｓｔＬｅｆｔ＿ｎｕｌｌ（ＳｔｒｉｎｇＵｔｉｌｓＴｅｓｔ．ｊａｖａ：２）
ここで、１行目の記述“ｊａｖａ．ｌａｎｇ．ＡｓｓｅｒｔｉｏｎＥｒｒｏｒ”は、例外クラス名である。また、１行目の記述“ｅｘｐｅｃｔｅｄ  ｓａｍｅ：＜ｎｕｌｌ＞  ｗａｓ  ｎｏｔ：＜＞”はエラーメッセージである。
【０１０３】
２行目の記述“ａｔ  ＳｔｒｉｎｇＵｔｉｌｓＴｅｓｔ．ｔｅｓｔＬｅｆｔ＿ｎｕｌｌ”は、例外に関連するメソッドがテストコード８０におけるｔｅｓｔＬｅｆｔ＿ｎｕｌｌメソッドであることを示す。また、２行目の記述“（ＳｔｒｉｎｇＵｔｉｌｓＴｅｓｔ．ｊａｖａ：２）”は、ｔｅｓｔＬｅｆｔ＿ｎｕｌｌメソッドが、テストコード８０（ファイル名“ＳｔｒｉｎｇＵｔｉｌｓＴｅｓｔ．ｊａｖａ”）の２行目のステートメントに記述されていることを示す。
【０１０４】
例外テーブル１２１には、他の例外ＩＤに対しても、例外とスタックトレースの内容が登録される。ここで、以下の説明では、例外ＩＤ“Ｅ１”の例外を例外Ｅ１のように表記する。
【０１０５】
図１９は、関連テーブルの例を示す図である。関連テーブル１３１は、テスト実行部１７０により生成され、関連情報記憶部１３０に格納される。関連テーブル１３１は、ミュータントＩＤおよび例外ＩＤの項目を含む。ミュータントＩＤの項目には、ミュータントＩＤが登録される。例外ＩＤの項目には、例外ＩＤが登録される。
【０１０６】
例えば、関連テーブル１３１には、ミュータントＩＤが“Ｍ１”、例外ＩＤが“Ｅ１，Ｅ２，Ｅ３”というレコードを含む。このレコードは、ミュータントＭ１に対して、テストコード８０を実行した場合に例外Ｅ１，Ｅ２，Ｅ３が発生したことを示す。
【０１０７】
関連テーブル１３１には、他のミュータントに対しても、テスト実行により発生した例外の例外ＩＤが対応づけて登録されている。
図２０は、実行時間テーブルの例を示す図である。実行時間テーブル１４１は、テスト実行部１７０により生成され、実行時間記憶部１４０に格納される。実行時間テーブル１４１は、ミュータントＩＤおよび実行時間の項目を含む。ミュータントＩＤの項目には、ミュータントＩＤが登録される。実行時間の項目には、テストコード８０によるミュータントＭ１のテスト実行に要した時間（実行時間）が登録される。実行時間の単位は、例えば、秒である。
【０１０８】
例えば、実行時間テーブル１４１には、ミュータントＩＤが“Ｍ１”、実行時間が“０．０１０”秒というレコードが登録されている。このレコードは、テストコード８０によるミュータントＭ１のテスト実行に要した時間が０．０１０秒であることを示す。
【０１０９】
実行時間テーブル１４１には、他のミュータントに対しても、実行時間が登録されている。
図２１は、選択済ミュータントテーブルの例を示す図である。選択済ミュータントテーブル１５１は、ミュータント選択部１８０により生成され、選択済ミュータント記憶部１５０に格納される。選択済ミュータントテーブル１５１は、ミュータントＩＤおよびミューテーション記述子の項目を含む。ミュータントＩＤの項目には、ミュータントＩＤが登録される。ミューテーション記述子の項目には、ミューテーション記述子が登録される。
【０１１０】
例えば、選択済ミュータントテーブル１５１には、ミュータントＩＤが“Ｍ１”、ミューテーション記述子が“２行目：“＝＝”−＞“！＝””というレコードが登録されている。このレコードは、ミュータント選択部１８０によりミュータントＭ１が選択されたことを示す。
【０１１１】
選択済ミュータントテーブル１５１には、ミュータント選択部１８０により選択された他のミュータントを示すレコードも登録されている。
図２２は、ミュータント選択の結果レポートの出力例を示す図である。結果レポート９０は、選択済ミュータント記憶部１５０に記憶された選択済ミュータントテーブル１５１に基づいて、結果出力部１９０により作成され、出力される。例えば、結果出力部１９０は、結果レポート９０を示す画面を、ディスプレイ１１に表示させる。
【０１１２】
結果レポート９０は、テスト対象プログラム６０に対してミュータント生成部１６０により生成された全ミュータントのうち、ミュータント選択部１８０により選択されたミュータントを示す。本例では、全ミュータントは、全ミュータントテーブル１１１に登録されているミュータントであり、合計１４個である。例えば、結果レポート９０の左側に全ミュータントの一覧が表示される。また、選択済ミュータントは、選択済ミュータントテーブル１５１に登録されているミュータントであり、合計８個である。例えば、結果レポート９０の右側に選択済ミュータントの一覧が表示される。
【０１１３】
ユーザは、結果レポート９０を確認することで、ミュータントの選択状況（ミュータントの削減状況）を把握することができる。また、ユーザは、以後のミューテーション解析を、選択済ミュータントを用いて行うことができる。
【０１１４】
図２３は、ミューテーション解析の結果レポートの出力例を示す図である。結果レポート９１は、テスト実行部１７０によるミューテーション解析の結果に基づいて、結果出力部１９０により作成され、出力される。例えば、テスト実行部１７０は、図２２で例示した８個の選択済ミュータントを用いて、テスト対象プログラム６０あるいはテスト対象プログラム６０に類似する別のテスト対象プログラムのミューテーション解析を行うことができる。
【０１１５】
結果レポート９１は、一例として、ｌｅｆｔメソッドに対するミュータント解析の結果を表す。結果レポート９１は、ミューテーションスコアの計算結果（例えば、“１００％”（８／８）の表示）やミューテーション解析に利用されたミュータントのリストを含む。ミューテーションスコアは、テストのバグ検出能力を示す指標である。ミューテーションスコアが大きいほど、バグ検出能力が高いことを示す。リストの１要素は、ソースコードの位置、オリジナルのコード、および、ミュータントのコードを含む。該当の位置において複数のミュータントを生成した場合は、該当の位置に対する複数のミュータントが表示され得る。ユーザは、リストから任意のミュータントを選択可能である。結果出力部１９０は、ユーザにより選択されたミュータントに対応するソースコード（テスト対象プログラム６０）の該当箇所を結果レポート９１内に表示させる。例えば、結果出力部１９０は、該当箇所を強調するようハイライト表示したり、該当箇所に下線を付したりすることで、ユーザによる問題箇所の認識を支援する。ユーザは、結果レポート９１を確認して、ミューテーションスコアを向上させるようテスト内容の見直しを行える。
【０１１６】
次に、解析装置１００によるミュータント選択の手順を説明する。
図２４は、ミュータント選択例を示すフローチャートである。
（Ｓ１）ミュータント生成部１６０は、テスト対象プログラム６０が入力されると、テスト対象プログラム６０から、テスト対象プログラム６０に対応する全てのミュータントを生成する。ミュータント生成部１６０は、全ミュータントを示す全ミュータントテーブル１１１を生成し、全ミュータント記憶部１１０に格納する。ミュータント生成部１６０は、生成したミュータントに対してコンパイルを行う場合、当該コンパイルを実行してオブジェクトコードを生成し、全ミュータント記憶部１１０に格納する。
【０１１７】
（Ｓ２）テスト実行部１７０は、全ミュータントのうち、新たなミュータントを取得する。新たなミュータントとは、ステップＳ３以降の処理を行っていないミュータントである。テスト実行部１７０は、取得したミュータントに関して実行時間の計測を開始する。
【０１１８】
（Ｓ３）テスト実行部１７０は、ステップＳ２で取得したミュータントに対して、テストコード８０に基づき、未実行のテストを実行する。ここでいう「テスト」は、テストコード８０の１つのメソッドに相当する。
【０１１９】
（Ｓ４）テスト実行部１７０は、ステップＳ３で実行したテストが失敗したか否かを判定する。テストが失敗（ｆａｉｌ）した場合、ステップＳ５に処理が進む。テストが成功（ｐａｓｓ）した場合、ステップＳ８に処理が進む。
【０１２０】
（Ｓ５）テスト実行部１７０は、例外発生に伴って出力されたスタックトレースに基づいて、今回のテスト失敗で発生した例外が未発生の例外であるか否かを判定する。未発生の例外である場合、ステップＳ６に処理が進む。発生済の例外である場合、ステップＳ７に処理が進む。テスト実行部１７０は、今回出力されたスタックトレースの内容と、例外テーブル１２１に登録済のスタックトレースの内容とを比較することで、ステップＳ５の判定を行える。今回の例外クラス名やスタックトレースの内容に一致する内容が、例外テーブル１２１に登録済であれば、今回の例外は発生済の例外である。一方、今回の例外クラス名やスタックトレースの内容に一致する内容が、例外テーブル１２１に未登録であれば、今回の例外は未発生の例外である。
【０１２１】
（Ｓ６）テスト実行部１７０は、今回発生した例外を記録する。具体的には、テスト実行部１７０は、例外に対して出力されたスタックトレースを取得し、例外ＩＤを付与して、例外ＩＤとスタックトレースの内容とを例外テーブル１２１に登録する。
【０１２２】
（Ｓ７）テスト実行部１７０は、ミュータントと例外との関連を記録する。具体的には、テスト実行部１７０は、今回テストしたミュータントのミュータントＩＤと発生した例外の例外ＩＤとを対応づけて、関連テーブル１３１に登録する。
【０１２３】
（Ｓ８）テスト実行部１７０は、ステップＳ２で取得したミュータントに対して、テストコード８０に含まれる全てのテストが実行されたか否かを判定する。該当のミュータントに対してテストコード８０に含まれる全てのテストが実行された場合、ステップＳ９に処理が進む。該当のミュータントに対してテストコード８０に含まれる全てのテストが実行されていない場合、ステップＳ３に処理が進む。ここで、「全てのテスト」とは、テストコード８０の全てのメソッドに相当する。
【０１２４】
（Ｓ９）テスト実行部１７０は、今回テスト実行したミュータントの実行時間を実行時間テーブル１４１に記録する。
（Ｓ１０）テスト実行部１７０は、全ミュータントテーブル１１１に登録された全てのミュータントが実行されたか否かを判定する。全てのミュータントが実行された場合、ステップＳ１１に処理が進む。未実行のミュータントがある場合、ステップＳ２に処理が進む。
【０１２５】
（Ｓ１１）ミュータント選択部１８０は、例外テーブル１２１と関連テーブル１３１と実行時間テーブル１４１とに基づいて、例外テーブル１２１に登録された例外を全てカバーする最小のミュータント集合を算出する。例えば、ミュータント選択部１８０は、例外テーブル１２１に登録された例外の集合を集合Ｕとし、関連テーブル１３１の例外ＩＤの項目に登録された例外の組（集合Ｕの部分集合）の集合を集合Ｓとして、集合被覆問題を解く。すなわち、ミュータント選択部１８０は、集合Ｕの要素を全てカバーするように、集合Ｓからコスト（集合Ｓから選ぶ要素の数や、実行時間など）が最小となる集合Ｕの部分集合の組み合わせを選ぶ。ミュータント選択部１８０は、選択したミュータントを、選択済ミュータントテーブル１５１に登録する。
【０１２６】
（Ｓ１２）結果出力部１９０は、全ミュータントテーブル１１１および選択済ミュータントテーブル１５１に基づいて、結果レポート９０を生成し、出力する。例えば、結果出力部１９０は、結果レポート９０をディスプレイ１１に表示させ、ユーザに提示する。
【０１２７】
なお、ステップＳ１では、ミュータント生成部１６０は、全てのミュータントを予め生成するのではなく、全てのミュータントＩＤとミューテーション記述子とを全ミュータントテーブル１１１に登録しておいてもよい。そして、ミュータント生成部１６０は、あるミュータントのテスト実行を開始する直前に（ステップＳ２で）、全ミュータントテーブル１１１に含まれるミューテーション記述子に基づき、当該ミュータントを生成し、全ミュータント記憶部１１０に格納してもよい。
【０１２８】
このように、解析装置１００は、例外テーブル１２１におけるスタックトレースに基づいて、複数のミュータントのうちミューテーション解析に用いるミュータントを選択する。具体的には、解析装置１００は、スタックトレースを参照して、発生した例外をミュータントごとに特定する。そして、解析装置１００は、発生した全ての例外を網羅するミュータントの組のうちミューテーション解析の実行コストが小さい組を優先的に選択する。例えば、解析装置１００は、ミュータントの数が最小の組を選択してもよい。または、解析装置１００は、ミュータントの実行時間の和が最小の組を選択してもよい。
【０１２９】
次に、テスト対象プログラム６０の各ミュータントに対してテストコード８０によるテストを実行した場合に発生する例外およびスタックトレースを具体的に説明する。
図２５は、ミュータントに対する例外の例（その１）を示す図である。図２５（Ａ）は、ミュータントＭ１に対応するソースコード６１を示す。なお、以下の説明において、テスト対象プログラム６０から作成されたミュータントのソースコードの名称を“ＳｔｒｉｎｇＵｔｉｌｓ．ｊａｖａ”とする。ソースコード６１は、テスト対象プログラム６０の２行目の“＝＝”を“！＝”に置換したものである。
【０１３０】
図２５（Ｂ）は、ミュータントＭ１に対して発生する例外の例を示す。ミュータントＭ１をテスト実行すると、テストコード８０の２行目のステートメントに対して例外Ｅ１が発生する。例外Ｅ１のスタックトレースは、テストコード８０の２行目のステートメントに関する例外であることを示す情報“ａｔ  ＳｔｒｉｎｇＵｔｉｌｓＴｅｓｔ．ｔｅｓｔＬｅｆｔ＿ｎｕｌｌ（ＳｔｒｉｎｇＵｔｉｌｓＴｅｓｔ．ｊａｖａ：２）”を含む。
【０１３１】
また、ミュータントＭ１をテスト実行すると、テストコード８０の７行目のステートメントに対して例外Ｅ２が発生する。例外Ｅ２のスタックトレースは、テストコード８０の７行目のステートメントに関する例外であることを示す情報“ａｔ  ＳｔｒｉｎｇＵｔｉｌｓＴｅｓｔ．ｔｅｓｔＬｅｆｔ＿ｅｍｐｔｙ（ＳｔｒｉｎｇＵｔｉｌｓＴｅｓｔ．ｊａｖａ：７）”を含む。
【０１３２】
更に、ミュータントＭ１をテスト実行すると、テストコード８０の１２行目のステートメントに対して例外Ｅ３が発生する。例外Ｅ３のスタックトレースは、テストコード８０の１２行目のステートメントに関する例外であることを示す情報“ａｔ  ＳｔｒｉｎｇＵｔｉｌｓＴｅｓｔ．ｔｅｓｔＬｅｆｔ＿ｖａｌｉｄ（ＳｔｒｉｎｇＵｔｉｌｓＴｅｓｔ．ｊａｖａ：１２）”を含む。
【０１３３】
図２６は、ミュータントに対する例外の例（その２）を示す図である。図２６（Ａ）は、ミュータントＭ２に対応するソースコード６２を示す。ソースコード６２は、テスト対象プログラム６０の２行目の“ｓｔｒ＝＝ｎｕｌｌ”を“ｆａｌｓｅ”に置換したものである。
【０１３４】
図２６（Ｂ）は、ミュータントＭ２に対して発生する例外の例を示す。ミュータントＭ２をテスト実行すると、テストコード８０の２行目のステートメントに対して例外Ｅ１が発生する。
【０１３５】
図２７は、ミュータントに対する例外の例（その３）を示す図である。図２７（Ａ）は、ミュータントＭ３に対応するソースコード６３を示す。ソースコード６３は、テスト対象プログラム６０の２行目の“ｓｔｒ＝＝ｎｕｌｌ”を“ｔｒｕｅ”に置換したものである。
【０１３６】
図２７（Ｂ）は、ミュータントＭ３に対して発生する例外の例を示す。ミュータントＭ３をテスト実行すると、テストコード８０の７行目のステートメントに対して例外Ｅ２が発生する。また、ミュータントＭ３をテスト実行すると、テストコード８０の１２行目のステートメントに対して例外Ｅ３が発生する。
【０１３７】
図２８は、ミュータントに対する例外の例（その４）を示す図である。図２８（Ａ）は、ミュータントＭ４に対応するソースコード６４を示す。ソースコード６４は、テスト対象プログラム６０の５行目の“＜”を“＞＝”に置換したものである。
【０１３８】
図２８（Ｂ）は、ミュータントＭ４に対して発生する例外の例を示す。ミュータントＭ４をテスト実行すると、テストコード８０の７行目のステートメントに対して例外Ｅ４が発生する。例外Ｅ４のスタックトレースは、テストコード８０の７行目のステートメントに関する例外であることを示す情報“ａｔ  ＳｔｒｉｎｇＴｅｓｔ．ｔｅｓｔＬｅｆｔ＿ｅｍｐｔｙ（ＳｔｒｉｎｇＵｔｉｌｓＴｅｓｔ．ｊａｖａ：７）”を含む。例外Ｅ４のスタックトレースは、ソースコード６４（ＳｔｒｉｎｇＵｔｉｌｓ．ｊａｖａ）の１１行目のステートメントに関する例外であることを示す情報“ａｔ  ＳｔｒｉｎｇＵｔｉｌｓ．ｌｅｆｔ（ＳｔｒｉｎｇＵｔｉｌｓ．ｊａｖａ：１１）”を含む。
【０１３９】
また、ミュータントＭ４をテスト実行すると、テストコード８０の１２行目のステートメントに対して例外Ｅ５が発生する。例外Ｅ５のスタックトレースは、テストコード８０の１２行目のステートメントに関する例外であることを示す情報“ａｔ  ＳｔｒｉｎｇＵｔｉｌｓＴｅｓｔ．ｔｅｓｔＬｅｆｔ＿ｖａｌｉｄ（ＳｔｒｉｎｇＵｔｉｌｓＴｅｓｔ．ｊａｖａ：１２）”を含む。例外Ｅ５のスタックトレースは、ソースコード６４の１１行目のステートメントに関する例外であることを示す情報“ａｔ  ＳｔｒｉｎｇＵｔｉｌｓ．ｌｅｆｔ（ＳｔｒｉｎｇＵｔｉｌｓ．ｊａｖａ：１１）”を含む。
【０１４０】
図２９は、ミュータントに対する例外の例（その５）を示す図である。図２９（Ａ）は、ミュータントＭ５に対応するソースコード６５を示す。ソースコード６５は、テスト対象プログラム６０の５行目の“ｌｅｎ  ＜  ０”を“ｆａｌｓｅ”に置換したものである。
【０１４１】
図２９（Ｂ）は、ミュータントＭ５に対して発生する例外の例を示す。ミュータントＭ５をテスト実行すると、テストコード８０の７行目のステートメントに対して例外Ｅ４が発生する。また、ミュータントＭ５をテスト実行すると、テストコード８０の１２行目のステートメントに対して例外Ｅ５が発生する。
【０１４２】
図３０は、ミュータントに対する例外の例（その６）を示す図である。図３０（Ａ）は、ミュータントＭ６に対応するソースコード６６を示す。ソースコード６６は、テスト対象プログラム６０の５行目の“ｌｅｎ  ＜  ０”を“ｔｒｕｅ”に置換したものである。
【０１４３】
図３０（Ｂ）は、ミュータントＭ６に対して発生する例外の例を示す。ミュータントＭ６をテスト実行すると、テストコード８０の１４行目のステートメントに対して例外Ｅ６が発生する。例外Ｅ６のスタックトレースは、テストコード８０の１４行目のステートメントに関する例外であることを示す情報“ａｔ  ＳｔｒｉｎｇＵｔｉｌｓＴｅｓｔ．ｔｅｓｔＬｅｆｔ＿ｖａｌｉｄ（ＳｔｒｉｎｇＵｔｉｌｓＴｅｓｔ．ｊａｖａ：１４）”を含む。
【０１４４】
図３１は、ミュータントに対する例外の例（その７）を示す図である。図３１（Ａ）は、ミュータントＭ７に対応するソースコード６７を示す。ソースコード６７は、テスト対象プログラム６０の６行目の“ＥＭＰＴＹ”を“ｎｕｌｌ”に置換したものである。
【０１４５】
図３１（Ｂ）は、ミュータントＭ７に対して発生する例外の例を示す。ミュータントＭ７をテスト実行すると、テストコード８０の７行目のステートメントに対して例外Ｅ２が発生する。また、ミュータントＭ７をテスト実行すると、テストコード８０の１２行目のステートメントに対して例外Ｅ３が発生する。
【０１４６】
図３２は、ミュータントに対する例外の例（その８）を示す図である。図３２（Ａ）は、ミュータントＭ８に対応するソースコード６８を示す。ソースコード６８は、テスト対象プログラム６０の８行目の“＜＝”を“＞”に置換したものである。
【０１４７】
図３２（Ｂ）は、ミュータントＭ８に対して発生する例外の例を示す。ミュータントＭ８をテスト実行すると、テストコード８０の９行目のステートメントに対して例外Ｅ７が発生する。例外Ｅ７のスタックトレースは、テストコード８０の９行目のステートメントに関する例外であることを示す情報“ａｔ  ＳｔｒｉｎｇＵｔｉｌｓＴｅｓｔ．ｔｅｓｔＬｅｆｔ＿ｅｍｐｔｙ（ＳｔｒｉｎｇＵｔｉｌｓＴｅｓｔ．ｊａｖａ：９）”を含む。例外Ｅ７のスタックトレースは、ソースコード６８（ＳｔｒｉｎｇＵｔｉｌｓ．ｊａｖａ）の１１行目のステートメントに関する例外であることを示す情報“ａｔ  ＳｔｒｉｎｇＵｔｉｌｓ．ｌｅｆｔ（ＳｔｒｉｎｇＵｔｉｌｓ．ｊａｖａ：１１）”を含む。
【０１４８】
また、ミュータントＭ８をテスト実行すると、テストコード８０の１３行目のステートメントに対して例外Ｅ８が発生する。例外Ｅ８のスタックトレースは、テストコード８０の１３行目のステートメントに関する例外であることを示す情報“ａｔ  ＳｔｒｉｎｇＵｔｉｌｓＴｅｓｔ．ｔｅｓｔＬｅｆｔ＿ｖａｌｉｄ（ＳｔｒｉｎｇＵｔｉｌｓＴｅｓｔ．ｊａｖａ：１３）”を含む。
【０１４９】
図３３は、ミュータントに対する例外の例（その９）を示す図である。図３３（Ａ）は、ミュータントＭ９に対応するソースコード６９を示す。ソースコード６９は、テスト対象プログラム６０の８行目の“ｓｔｒ．ｌｅｎｇｔｈ（）  ＜＝  ｌｅｎ”を“ｆａｌｓｅ”に置換したものである。
【０１５０】
図３３（Ｂ）は、ミュータントＭ９に対して発生する例外の例を示す。ミュータントＭ９をテスト実行すると、テストコード８０の９行目のステートメントに対して例外Ｅ７が発生する。
【０１５１】
また、ミュータントＭ９をテスト実行すると、テストコード８０の１５行目のステートメントに対して、例外Ｅ９が発生する。例外Ｅ９のスタックトレースは、テストコード８０の１５行目のステートメントに関する例外であることを示す情報“ａｔ  ＳｔｒｉｎｇＵｔｉｌｓＴｅｓｔ．ｔｅｓｔＬｅｆｔ＿ｖａｌｉｄ（ＳｔｒｉｎｇＵｔｉｌｓＴｅｓｔ．ｊａｖａ：１５）”を含む。例外Ｅ９のスタックトレースは、ソースコード６９（ＳｔｒｉｎｇＵｔｉｌｓ．ｊａｖａ）の１１行目のステートメントに関する例外であることを示す情報“ａｔ  ＳｔｒｉｎｇＵｔｉｌｓ．ｌｅｆｔ（ＳｔｒｉｎｇＵｔｉｌｓ．ｊａｖａ：１１）”を含む。
【０１５２】
図３４は、ミュータントに対する例外の例（その１０）を示す図である。図３４（Ａ）は、ミュータントＭ１０に対応するソースコード７０を示す。ソースコード７０は、テスト対象プログラム６０の８行目の“ｓｔｒ．ｌｅｎｇｔｈ（）  ＜＝  ｌｅｎ”を“ｔｒｕｅ”に置換したものである。
【０１５３】
図３４（Ｂ）は、ミュータントＭ１０に対して発生する例外の例を示す。ミュータントＭ１０をテスト実行すると、テストコード８０の１３行目のステートメントに対して例外Ｅ８が発生する。
【０１５４】
図３５は、ミュータントに対する例外の例（その１１）を示す図である。図３５（Ａ）は、ミュータントＭ１１に対応するソースコード７１を示す。ソースコード７１は、テスト対象プログラム６０の９行目の“ｓｔｒ”を“ｎｕｌｌ”に置換したものである。
【０１５５】
図３５（Ｂ）は、ミュータントＭ１１に対して発生する例外の例を示す。ミュータントＭ１１をテスト実行すると、テストコード８０の８行目のステートメントに対して例外Ｅ１０が発生する。例外Ｅ１０は、テストコード８０の８行目のステートメントに関する例外であることを示す情報“ａｔ  ＳｔｒｉｎｇＵｔｉｌｓＴｅｓｔ．ｔｅｓｔＬｅｆｔ＿ｅｍｐｔｙ（ＳｔｒｉｎｇＵｔｉｌｓＴｅｓｔ．ｊａｖａ：８）”を含む。
【０１５６】
また、ミュータントＭ１１をテスト実行すると、テストコード８０の１５行目のステートメントに対して例外Ｅ１１が発生する。例外Ｅ１１のスタックトレースは、テストコード８０の１５行目のステートメントに関する例外であることを示す情報“ａｔ  ＳｔｒｉｎｇＵｔｉｌｓＴｅｓｔ．ｔｅｓｔＬｅｆｔ＿ｖａｌｉｄ（ＳｔｒｉｎｇＵｔｉｌｓＴｅｓｔ．ｊａｖａ：１５）”を含む。
【０１５７】
図３６は、ミュータントに対する例外の例（その１２）を示す図である。図３６（Ａ）は、ミュータントＭ１２に対応するソースコード７２を示す。ソースコード７２は、テスト対象プログラム６０の１１行目の“０”を“１”に置換したものである。
【０１５８】
図３６（Ｂ）は、ミュータントＭ１２に対して発生する例外の例を示す。ミュータントＭ１２をテスト実行すると、テストコード８０の１３行目のステートメントに対して例外Ｅ１２が発生する。例外Ｅ１２のスタックトレースは、テストコード８０の１３行目のステートメントに関する例外であることを示す情報“ａｔ  ＳｔｒｉｎｇＵｔｉｌｓＴｅｓｔ．ｔｅｓｔＬｅｆｔ＿ｖａｌｉｄ（ＳｔｒｉｎｇＵｔｉｌｓＴｅｓｔ．ｊａｖａ１３）”を含む。例外Ｅ１２のスタックトレースは、ソースコード７２（ＳｔｒｉｎｇＵｔｉｌｓ．ｊａｖａ）の１１行目のステートメントに関する例外であることを示す情報“ａｔ  ＳｔｒｉｎｇＵｔｉｌｓ．ｌｅｆｔ（ＳｔｒｉｎｇＵｔｉｌｓ．ｊａｖａ：１１）”を含む。
【０１５９】
図３７は、ミュータントに対する例外の例（その１３）を示す図である。図３７（Ａ）は、ミュータントＭ１３に対応するソースコード７３を示す。ソースコード７３は、テスト対象プログラム６０の１１行目の“ｓｔｒ．ｓｕｂｓｔｒｉｎｇ（０，  ｌｅｎ）”を“ｎｕｌｌ”に置換したものである。
【０１６０】
図３７（Ｂ）は、ミュータントＭ１３に対して発生する例外の例を示す。ミュータントＭ１３をテスト実行すると、テストコード８０の１３行目のステートメントに対して例外Ｅ１３が発生する。例外Ｅ１３のスタックトレースは、テストコード８０の１３行目のステートメントに関する例外であることを示す情報“ａｔ  ＳｔｒｉｎｇＵｔｉｌｓＴｅｓｔ．ｔｅｓｔＬｅｆｔ＿ｖａｌｉｄ（ＳｔｒｉｎｇＵｔｉｌｓＴｅｓｔ．ｊａｖａ：１３）”を含む。
【０１６１】
図３８は、ミュータントに対する例外の例（その１４）を示す図である。図３８（Ａ）は、ミュータントＭ１４に対応するソースコード７４を示す。ソースコード７４は、テスト対象プログラム６０の１１行目の“ｓｔｒ．ｓｕｂｓｔｒｉｎｇ（０，  ｌｅｎ）”を“ｓｔｒ”に置換したものである。
【０１６２】
図３８（Ｂ）は、ミュータントＭ１４に対して発生する例外の例を示す。ミュータントＭ１４をテスト実行すると、テストコード８０の１３行目のステートメントに対して例外Ｅ８が発生する。
【０１６３】
図３９は、ミュータントと例外との関連の例を示す図である。テスト実行部１７０は、テスト実行したミュータントと、当該ミュータントに対して発生した例外（または当該例外のスタックトレース）とを関連づける関連テーブル１３１を生成し、関連情報記憶部１３０に格納する。図３９では、図１９の関連テーブル１３１および図２５〜図３８で例示したミュータントと例外のスタックトレースとの関連を示している。
【０１６４】
ミュータントＭ１は、例外Ｅ１，Ｅ２，Ｅ３に関連づけられる。ここで、例えば、例外Ｅ１のスタックトレースは、例外Ｅ１の関連箇所がテストコード８０の２行目のステートメントであることを示す。したがって、関連テーブル１３１は、ミュータントＭ１と、テストコード８０の２行目のステートメントを関連づけているともいえる。同様に、関連テーブル１３１は、ミュータントＭ１とテストコード８０の７行目のステートメントを関連づけているともいえる。
【０１６５】
また、ミュータントＭ２は、例外Ｅ１に関連づけられる。ミュータントＭ３は、例外Ｅ２，Ｅ３に関連づけられる。ミュータントＭ４は、例外Ｅ４，Ｅ５に関連づけられる。ミュータントＭ５は、例外Ｅ４，Ｅ５に関連づけられる。ミュータントＭ６は、例外Ｅ６に関連づけられる。ミュータントＭ７は、例外Ｅ２，Ｅ３に関連づけられる。ミュータントＭ８は、例外Ｅ７，Ｅ８に関連づけられる。ミュータントＭ９は、例外Ｅ７，Ｅ９に関連づけられる。ミュータントＭ１０は、例外Ｅ８に関連づけられる。ミュータントＭ１１は、例外Ｅ１０，Ｅ１１に関連づけられる。ミュータントＭ１２は、例外Ｅ１２に関連づけられる。ミュータントＭ１３は、例外Ｅ１３に関連づけられる。ミュータントＭ１４は、例外Ｅ８に関連づけられる。
【０１６６】
図４０は、関連に基づくミュータント選択の例を示す図である。ミュータント選択部１８０は、例えば、例外Ｅ１〜Ｅ１３を全てカバーし、かつ、実行時間の総和が最小になるミュータントの組合せを選択する。各ミュータントの実行時間は、実行時間記憶部１４０に格納された実行時間テーブル１４１に記録されている。図４０の例では、ミュータント選択部１８０は、ミュータントＭ１，Ｍ４，Ｍ６，Ｍ８，Ｍ９，Ｍ１１，Ｍ１２，Ｍ１３を選択する。
【０１６７】
図４１は、ミュータントの選択結果の例を示す図である。ミュータント選択部１８０は、ミュータントの選択結果を、選択済ミュータント記憶部１５０に格納された選択済ミュータントテーブル１５１に登録する。図４１によれば、図２５〜図３８のテスト実行により発生した全ての例外Ｅ１〜Ｅ１３がカバーされていることが分かる。
【０１６８】
ここで、ミュータント選択の比較例について説明する。
図４２は、ミュータント選択の比較例を示す図である。１つの方法として、スタックトレースを考慮せずに、テストコード８０における例外に関連するメソッドのパターンを全て網羅するようにミュータントを選択することも考えられる。例えば、ミュータントＭ１では、ｔｅｓｔＬｅｆｔ＿ｎｕｌｌメソッド、ｔｅｓｔＬｅｆｔ＿ｅｍｐｔｙメソッドおよびｔｅｓｔＬｅｆｔ＿ｖａｌｉｄメソッドで例外が発生する。このパターンをｓｔｒａｔｕｍ“１”と呼ぶこととする。
【０１６９】
また、ミュータントＭ２では、ｔｅｓｔＬｅｆｔ＿ｎｕｌｌメソッドのみで例外が発生する。このパターンをｓｔｒａｔｕｍ“２”と呼ぶこととする。
また、ミュータントＭ３では、ｔｅｓｔＬｅｆｔ＿ｅｍｐｔｙメソッドおよびｔｅｓｔＬｅｆｔ＿ｖａｌｉｄメソッドで例外が発生する。このパターンをｓｔｒａｔｕｍ“３”と呼ぶこととする。
【０１７０】
また、ミュータントＭ４では、ｔｅｓｔＬｅｆｔ＿ｅｍｐｔｙメソッドおよびｔｅｓｔＬｅｆｔ＿ｖａｌｉｄメソッドで例外が発生する。このパターンは、ｓｔｒａｔｕｍ“３”である。
【０１７１】
更に、ミュータントＭ５では、ｔｅｓｔＬｅｆｔ＿ｖａｌｉｄメソッドのみで例外が発生する。このパターンをｓｔｒａｔｕｍ“４”と呼ぶこととする。
このように、ミュータントＭ１〜Ｍ１４のテスト実行に応じて、テストコード８０の例外に関連するメソッドのパターンを確認すると、ｓｔｒａｔｕｍ“１”、ｓｔｒａｔｕｍ“２”、ｓｔｒａｔｕｍ“３”、ｓｔｒａｔｕｍ“４”の４種類のパターンとなる。比較例では、この場合、４種類のパターンを全てカバーするように、ミュータントＭ１，Ｍ２，Ｍ３，Ｍ５が選択される。
【０１７２】
図４３は、ミュータント選択の比較例（続き）を示す図である。ミュータントＭ１，Ｍ２，Ｍ３，Ｍ５を選択し、ミュータントＭ４，Ｍ６〜Ｍ１４を削減すると、ミュータントＭ１，Ｍ２，Ｍ３，Ｍ５をテスト実行することで発生する例外は５つの例外Ｅ１〜Ｅ５となる。すなわち、選択後のミュータントＭ１，Ｍ２，Ｍ３，Ｍ５では、５つの例外しかカバーできず、例外Ｅ１〜Ｅ１３を全てカバーしていない。
【０１７３】
一方、テストコード８０の１つのテストケース（メソッド）で複数のミュータントがｋｉｌｌされるとき、ｋｉｌｌされる要因は単一でないことがある。例えば、ミュータントＭ１〜Ｍ１４に対して発生する例外によれば、テストコード８０の１つのメソッドに関して、異なる種類の複数の例外が発生し得る。しかし、比較例の方法では同じ１つの要因によるものと捉え、必要以上にミュータントを削減してしまう可能性がある。このため、テストコード８０のバグの検出能力を評価するために十分なミュータントが選択されない可能性がある。
【０１７４】
次に、前述のミュータントＭＴ１，ＭＴ２，ＭＴ３，ＭＴ４を用いて、ミューテーションスコアを適切に算出できない例を説明する。
図４４は、ミューテーション解析結果の比較例を示す図である。ミュータントＭＴ１，ＭＴ２，ＭＴ３，ＭＴ４は、同じテストケース（図１１のテストコード８０ａのｔｅｓｔＩｓＥｍｐｔｙメソッド）で全てｋｉｌｌされる。このため、ミュータントＭＴ１，ＭＴ２，ＭＴ３，ＭＴ４のうち、ミュータントＭＴ１が選択され、ミュータントＭＴ２，ＭＴ３，ＭＴ４が削減され得る。
【０１７５】
その後、テストコード８０ａが、テストコード８０ｂに書き換えられることを考える。テストコード８０ｂは、テストコード８０ａにおける４行目、５行目および６行目のステートメントがコメントアウトされている。テストコード８０ｂは、テストコード８０ａよりもバグ検出能力を落としたテストコードである。
【０１７６】
仮に、ミュータントＭＴ１，ＭＴ２，ＭＴ３，ＭＴ４の全てを用いて、テストコード８０ｂによるテストを行い、テストコード８０ｂのミューテーションスコアを評価することを考える。この場合、ミュータントＭＴ１，ＭＴ２はＦａｉｌである（ｋｉｌｌされる）。一方、ミュータントＭＴ３，ＭＴ４は、ｐａｓｓである（ｋｉｌｌされない）。よって、このときのミューテーションスコアは、２／４×１００＝５０％である。
【０１７７】
しかし、ミュータントＭＴ１のみを用いる場合、テストコード８０ｂのミューテーションスコアは、１／１×１００＝１００％となる。すなわち、比較例の方法で選択されたミュータントＭＴ１のみでは、バグ検出能力の正確な測定を行えない（すなわち、バグ検出能力の測定精度が低下する）。
【０１７８】
このような問題は、例えば、発生した例外のスタックトレースを考慮せずに、ミュータントの実行時間のみを考慮し、実行時間の総和が最小になるようにミュータントを選択する場合にも起こり得る。すなわち、実行速度のみが最適化され、テストを評価するために十分なミュータントが選択されない可能性がある。また、単に、テスト対象プログラムに含まれる全ての行をカバーするようにミュータントを選択する場合（例えば、１つの行に対してバグを埋め込んだミュータントを１つだけ選択する場合）にも起こり得る。すなわち、同じ行内のミュータントであっても異なる種類のバグであることもあり、テストを評価するために十分なミュータントが選択されない可能性がある。
【０１７９】
一方、解析装置１００によれば、スタックトレースに基づいて、ミュータントを選択する。
図４５は、解析装置によるミューテーション解析結果の例を示す図である。図１３で例示したように、解析装置１００は、テストコード８０ａによるテスト実行の結果、ミュータントＭＴ１，ＭＴ３を選択し、ミュータントＭＴ２，ＭＴ４を削減する。この場合、前述のテストコード８０ｂによるテストを行い、テストコード８０ｂのミューテーションスコアを評価すると、１／２×１００＝５０％となる。すなわち、解析装置１００は、図４４の比較例の方法を用いる場合よりも、ミュータント選択を行わない場合に近いミューテーションスコアを得ることができる。このように、解析装置１００によれば、ミュータントを削減可としながら、より正確なバグ検出能力を測定可能になる。
【０１８０】
解析装置１００によれば、テストケースが複数のステートメントを含む場合であっても、例外を発生させたミュータントとステートメントとの対応づけを行うことができる。テストケース単位であれば、テストケースの実行により例外が発生したか（例外の有無）を見れば済んでいた。一方、解析装置１００は、スタックトレースを参照して、例外の発生有無を確認することにより、テストケースに含まれるステートメント単位でミュータントがｋｉｌｌされたか否かを判断することができる。
【０１８１】
また、解析装置１００によれば、冗長な例外を発生させるミュータントを削減することで、ミューテーション解析を高速化できる。図５で例示したように、ミューテーション解析の実行時間は、ミュータントの数に比例する。したがって、ミュータントの数を削減することで、削減後に行うミューテーション解析の実行時間を短縮できる。更に、ミュータントごとに測定した実行時間に基づき、実行時間の総和が小さくなるように、ミューテーション解析に用いるミュータントを選択することで、ミューテーション解析の実行時間をより一層短縮することもできる。更に、解析装置１００は、検出された例外を全てカバーするようにミュータントを選択することで、ミュータントが過剰に削減されることを防げる。その結果、ミューテーション解析によるバグ検出能力の低下が抑えられ、より正確にバグ検出能力を測定可能になる。
【０１８２】
なお、第１の実施の形態の情報処理は、処理部１ｂにプログラムを実行させることで実現できる。また、第２の実施の形態の情報処理は、ＣＰＵ１０１にプログラムを実行させることで実現できる。プログラムは、コンピュータ読み取り可能な記録媒体１３に記録できる。
【０１８３】
例えば、プログラムを記録した記録媒体１３を配布することで、プログラムを流通させることができる。また、プログラムを他のコンピュータに格納しておき、ネットワーク経由でプログラムを配布してもよい。コンピュータは、例えば、記録媒体１３に記録されたプログラムまたは他のコンピュータから受信したプログラムを、ＲＡＭ１０２やＨＤＤ１０３などの記憶装置に格納し（インストールし）、当該記憶装置からプログラムを読み込んで実行してもよい。
【符号の説明】
【０１８４】
１  識別装置
１ａ  記憶部
１ｂ  処理部
２  テスト対象プログラム
３  テストコード
【図１】
2019128812.tif 000003
【図２】
2019128812.tif 000004
【図３】
2019128812.tif 000005
【図４】
2019128812.tif 000006
【図５】
2019128812.tif 000007
【図６】
2019128812.tif 000008
【図７】
2019128812.tif 000009
【図８】
2019128812.tif 000010
【図９】
2019128812.tif 000011
【図１０】
2019128812.tif 000012
【図１１】
2019128812.tif 000013
【図１２】
2019128812.tif 000014
【図１３】
2019128812.tif 000015
【図１４】
2019128812.tif 000016
【図１５】
2019128812.tif 000017
【図１６】
2019128812.tif 000018
【図１７】
2019128812.tif 000019
【図１８】
2019128812.tif 000020
【図１９】
2019128812.tif 000021
【図２０】
2019128812.tif 000022
【図２１】
2019128812.tif 000023
【図２２】
2019128812.tif 000024
【図２３】
2019128812.tif 000025
【図２４】
2019128812.tif 000026
【図２５】
2019128812.tif 000027
【図２６】
2019128812.tif 000028
【図２７】
2019128812.tif 000029
【図２８】
2019128812.tif 000030
【図２９】
2019128812.tif 000031
【図３０】
2019128812.tif 000032
【図３１】
2019128812.tif 000033
【図３２】
2019128812.tif 000034
【図３３】
2019128812.tif 000035
【図３４】
2019128812.tif 000036
【図３５】
2019128812.tif 000037
【図３６】
2019128812.tif 000038
【図３７】
2019128812.tif 000039
【図３８】
2019128812.tif 000040
【図３９】
2019128812.tif 000041
【図４０】
2019128812.tif 000042
【図４１】
2019128812.tif 000043
【図４２】
2019128812.tif 000044
【図４３】
2019128812.tif 000045
【図４４】
2019128812.tif 000046
【図４５】
2019128812.tif 000047