第4章で挙げた達成目標を,以下に再掲する.
これらの目標を達成できているか,以下の操作をトレースすることで評価する.
上記の項目について本システムを検証すべく,実際に実行中のサービスに対して 本システムによる制御を試みた.
評価実験では,サービスの要求呼び出しに相当するメソッドに対して以下の操作 を行う.
以下に,実験に用いたサービスであるCalculatorService
のコードを示す.
このサービスは,任意の演算子を用いて2項演算を行うcompute
というメ
ソッドを公開する.サポートされていない演算子を指定された場合は,例外をス
ローする.上述の操作は,compute
メソッドに対して実行される.
public class CalculatorService { private static HashMap<String, Operator> operatorMap; static { operatorMap = new HashMap<String, Operator>(); operatorMap.put("+", new PlusOperator()); operatorMap.put("plus", new PlusOperator()); operatorMap.put("-", new PlusOperator()); operatorMap.put("minus", new PlusOperator()); } // 抽象的な演算子クラス.サブクラスで2項演算を実装する abstract static class Operator{ private String name; private String symbol; Operator(String name, String symbol){ this.name = name; this.symbol = symbol; } abstract int operate(int x, int y); } // 加算演算子 Static Class PlusOperator extends Operator{ PlusOperator(){ super("plus", "+"); } int operate(int x, int y){ return x + y; } } // 減算演算子 static class MinusOperator extends Operator{ MinusOperator(){ super("minus", "-"); } int operate(int x, int y){ return x - y; } } // 演算子を指定して2項演算 public int compute(int x, int y, String operator){ if(!operatorMap.containsKey(operator)) throw new UnsupportedOperationException("\"" + operator + "\" is not supported."); else{ int retval = doCompute(x, y, operatorMap.get(operator)); return retval; } } private int doCompute(int x, int y, Operator op){ return op.operate(x, y); } }
CalculatorService
に対して前述の操作を行い,本システムによってコー
ドが期待通りに変換されていることを確認した.また,変換後のコードが本章の
冒頭に挙げた達成目標を満たすように動作することを確認し,機能性とその限界に
ついて評価を行った.以下,それぞれについて詳細を述べる.
compute
メソッドは,以下のソースコードと等価なバイトコー
ドに変換された(コメントは除く).メソッドの呼び出し前後と例外処理に,意図
した通りの処理が組み込まれている.
public class CalculatorService { public int compute(int x, int y, String op) { MessageDispatcher dispatcher = controller.getMessageDispatcher(); dispatcher.write("Method: setValue, x = " + x + , y = " + y); try{ // サポートされていない演算子はエラーで例外処理 if(!operatorMap.containsKey(operator)) throw new UnsupportedOperationException("\"" + operator + "\" is not supported."); else{ int retval = doCompute(x, y, operatorMap.get(operator)); dispatcher.write("Method: compute, retval = " + retval); return retval; }catch(Exception ex){ dispatcher.exec(ex); dispatcher.forward(ex); } }
例えば,あるビヘイビアとそのビヘイビア内から呼び出される他のビヘイビアのみ に着目し解析対象に指定する,といった使い方はできない.なぜなら,ビヘイビ アのボディは解析しないので,ビヘイビア呼び出しの一覧が取得できないからで ある.現状では呼び出されるタイミングでビヘイビア名を出力するコードをす べてのビヘイビアに挿入して,メッセージ内容を元に呼び出し順序を追跡するな ど,実行時に得られる情報から解析しなければならない.
したがって,無差別にビヘイビアの振る舞いをダンプするような使い方は可能で あるが,呼び出しの連鎖に含まれるビヘイビアのみを選択することはできない. より精度の高い情報を得るためには,ビヘイビアのボディを静的解析してコール グラフを作成する必要がある.詳細は考察で述べる.
この結果は,リクエスタサイドでプロバイダの振る舞いに対する事前条件および事後 条件を記述できるということを意味する[20].このことは,プロバイダで定義さ れた両条件を満たした上で,更にリクエスタのテスト要件に適した条件に絞りこ めるという有用性をもたらす.
Webサービスは例外をサポートしており,WSDLでfault
要素としてカス
タム例外を定義しておくことで,ポートタイプで発生した例外をリクエスタに送
信できる.しかし,例外をスローしたクラスやスタックトレースなどの情報は削
られてしまう.本システムを用いれば,例外オブジェクトをWebサービスフレー
ムワークが処理してSOAPメッセージ化する前にディスパッチするので,無劣化の
Java例外オブジェクトとして独自に処理可能である.
テスト要件に必要な内部情報のみを選定するためには,着目するサービスが呼 び出すビヘイビアの一覧が必要である.単純な方法であれば,すべてのビヘイビ アに対して呼び出し時にシグニチャを出力するようなコード断片を挿入し,実際 にサービスを要求して出力を解析すればよい.しかし,この方法ではすべてのビ ヘイビア呼び出しを完全に網羅できるとは限らない.ビヘイビアの相互関係を完 全に明らかにするためには,クラスオブジェクトを静的解析してコールグラフを 作成する必要がある.コールグラフとは,関数の呼び出し関係を有向エッジで結 び付けたグラフである.
ただし,実行時に決定される呼び出し関係は,静的に作成したコールグラフでは 把握できない.また,SOAPメッセージングなど本システムの解析対象に含まれな いRPCも,呼び出し関係とは見なされない.
前者については,実行時に生成したコールグラフで補えばよい.この場合,まだ ロードされていないコードは対象とならないが,そのようなコードは解析対象と なるポートタイプにとって重要でないと判断できるので,大きな問題にはならな いと考える.
後者は,言語仕様外のRPCを扱うための拡張が必要となる.この実現手法につい ては本システムの問題領域から外れるので,ここでは議論しない.
DbCでは,関数の呼び出し前後で満たすべき条件をそれぞれ事前条件,事後条 件と呼称し,プログラムとして記述する.これは,関数の仕様をプログラムとし て明文化することと同義である.
本システムの評価では,ビヘイビアの前後に引数や戻り値をチェックするコード を挿入し,検証に成功した.これは,リクエスタがプロバイダの内部動作に対 する事前条件,事後条件を表明できることを意味する.すなわち,プロバイダの 設計者による事前条件,事後条件を満たす範囲内で,リクエスタが意図する仕様 を条件として追加することで,より精緻なテスト要件が実現できるというこ とである.
例えば,あるビヘイビアの引数または戻り値が,プロバイダが意図した規約には適合して いたとしても,リクエスタ全体の振る舞いにおける部分動作としては不適切であ るというケースが考えられる.このような状況では,リクエスタ側が意図しない値は論理的な バグとみなし,実行時エラーとしてプロバイダに処理させるように,本システム を用いて事前または事後条件を更に制限すればよい.特に非公開ビヘ イビアに関してはプロバイダの処理系に処理と検証を任せざるを得ないので,本 システムを用いることではじめてプロバイダ内部に独自のテスト要件を織り込 むことが可能になる.
なお,DbCでは事前条件,事後条件の他に,クラス,メソッド,フィールドの不 変性を保証する契約として,不変条件の概念を提唱している.本システムにおいて リクエスタによる不変条件の表明を実現するためには,クラスやメンバを監視す るようなコードを実行時動的コード変換技術を用いて挿入すればよい.しかし, 一般にリクエスタはビヘイビアの振る舞いが及ぼす影響について知りたいのであっ て,ビヘイビアの不変性を保証できたところで有用性は少ないと考えられる. したがって,本システムでは不変条件をサポートしていない.
MITSUBAYASHI Shin 2007-03-14