シンボリック実行を利用したソフトウェアの互換性確認にかんする考察と実験

標準

従来の互換性確認テストプロセスとその網羅性

まず、従来の互換性を確認するテストについて考えます。下の図を見てください。

通常の互換性テストプロセス1

この図は、変更を加える前のソフトウェアのテストプロセスを表します。当たり前の話かもしれませんが、改めて確認しておきます。

変更前のソフトウェアの仕様をもとに、テストケースを作成します。テストケースは、テスト対象に与える「入力」と、期待する結果「期待値」のセットです。テストケースをテスト対象に対して実行し、得られた出力と、期待値を比較します。出力と期待値が一致すれば、PASS(テスト合格)です。不一致ならば、FAIL(テスト不合格)です。

次に変更を加えた後のソフトウェアのテストプロセスを示します。下図をご覧ください。

通常の互換性テストプロセス2

変更前ソフトウェアとの違いは、テストケースの部分です。変更後ソフトウェアのテストでは、変更前との互換性を確認するため、変更前のテストケースを再利用します。このテストがPASSすれば、互換性が確保されていると考えます。加えて、仕様が変更された部分に対するテストケースを作成し、実行します。

ここでテストの網羅性を考えます。単純な例として、あるソフトウェアを異なるプラットフォームへ移植、または内部設計をリファクタすることを想定してみます。このとき、3種類のバグが埋め込まれる可能性があります。すなわち、「削除」:必要な機能を誤って削除してしまう、「修正」:機能を誤って変更してしまう、「追加」:誤って不要な機能を追加してしまう、です。

 

テストの網羅性1

前述したテストプロセスで網羅できる範囲を下図に示します。変更前のソフトウェアをテストするテストケースを変更後のソフトウェアに対して再利用します。すると、検出できるバグは、「削除」と「修正」です。「追加」の部分は、変更前のソフトウェアに存在しなかった部分なので検出はできません。

テストの網羅性2

実際の現場では、再利用するテストの網羅性も怪しい場合が多く、古いソフトウェアになると存在すら怪しいこともあります。「削除」「修正」も見逃してしまうかもしれません。

シンボリック実行を組み込んだ互換テストプロセス

この課題を解決するために、シンボリック実行の技術を利用して、互換性を確認するテストプロセスを考えます。下図をご覧ください。これが全体像です。プロセスは大きく2つのステップで実施します。以下に説明します。

提案するテストプロセス

 

ステップ1

変更前のソフトウェアに対して、シンボリック実行を実施します。様々なフリーのツールが存在しますので、言語や環境に合わせてツールを選択します。実行した結果、入力データTCoが生成されます。また、そのデータを実行した出力値Ro2を得ます。次にTCoを変更後のソフトウェアに入力し、その結果、出力Rn2を得ます。得られた2つの出力Ro2, Rn2を比較することで互換性を確認します。すなわち、出力が一致した箇所は、論理的な挙動が同様であり、一致しない箇所は挙動が異なるということです。前述の例であげた移植やリファクタの場合であれば、一致しない箇所があるならば、それはバグであるといえます。

ステップ2

次に、変更後のソフトウェアに対して、シンボリック実行を実施します。実行した結果、入力データTCnが生成されます。また、そのデータを実行した出力値Rn1を得ます。次にTCnを変更前のソフトウェアに入力し、その結果、出力Ro1を得ます。得られた2つの出力Rn1, Ro1を比較することで互換性を確認します。

さて、再びテストの網羅性を考えます。前述の図に当てはめたとき、ステップ1で網羅できる範囲は下記の図のようになります。

テストの網羅性3

 

さらに、ステップ2で網羅できる範囲は下記のようになります。

テストの網羅性4

2つのステップをあわせることで、3種類のバグがすべて検出できることがわかります。おお、これでテスト網羅性は解決できましたね!

では、再利用するテストケースが貧弱(またはない)という課題はどうでしょうか。この方法では、テストケース(=入力データと出力結果)をツールによって自動生成しますので、既存のテストケースがなくてもかまいません。さらに、存在するパスを網羅するようなテストケースを生成しますので、論理的な挙動も網羅的に確認ができます。この点においても、課題を解決できました(※)

※ パス網羅だけでは確認できない観点(データの組み合わせとか)もありますので、これで万事OKというわけではない点はご留意ください

このテストプロセスを確認するために実験を行いました。