5. オブジェクト辞書の作成

5.1. 表題の標準化

メソッドテスト仕様書の表題を規定します。 オブジェクト辞書のCommonDicシートの「Hdr_」で始まる項目のB列に表題を指定します。 新しいテストシートを作成する際に、この表題が使用されます。

大域変数の冠:大域変数をJsonPathで設定することができます。大域変数の項目には、「大域変数の冠」で設定した文字列から始まります。

5.2. 共通マクロ

5.2.1. Jsonのテンプレートを設定する

クラスインスタンスの標準的な初期値をJsonで設定することができます。

これにより、TestSuiteシートでは、バリエーションテスト対象の属性の値だけを設定することに焦点を絞ることができます。

ReserveDicシートに、

A列(マクロ名)

B列(展開後の文字列)

sampleName

Json書式の文字列

と記述しておきます。

※ TestSuiteシートで値を設定する時には、引数のJsonPathの右の設定値欄に「sampleName(x,y,..)」と記述します。x,y,...はシンボルではなく、数字であったり文字列などの具体的な値です。 設定欄で使用された値ReserveDicシートに記載された定義文字列の中に$arg1、$arg2...があれば、x,y,...に置き換えられます。($argは予約語です。1,2,...は位置を示します)

※ マクロ名は可読性を重視し、一目で理解できるように命名するとよいでしょう。

5.2.2. 実行対象のオブジェクトや引数の初期値を生成するための準備

メソッドを実行するオブジェクトやメソッドの引数としてのオブジェクトが、デフォルトコンストラクタを持たない場合には、オブジェクトを生成するJavaコードを書いた方が容易になる場合があります。

クラスの標準的なインスタンスを生成する場合、ReservedDicシートに、

A列

B列

com.foo.Sample

#initialize

オブジェクトを生成して返すソースコード

を記述します。

5.2.3. 実行対象のオブジェクトや引数の属性オブジェクトを生成するためのマクロの設定

実行対象のオブジェクトや引数オブジェクトの属性がさらにデフォルトコンストラクタを持たないオブジェクトであることがあります。そのような場合には、ReserveDicシートに、次のようにマクロを記述しておきます。

A列(マクロ名#initialize)

B列(展開後の文字列)

sampleName#initialize

オブジェクトを生成するソースコード

TestSuiteシートで値を設定する時には、引数のJsonPathの右の設定値欄に「new sampleName(x,y,...)」と記述します。。x,y,...はシンボルではなく、数字であったり文字列などの具体的な値です。 設定欄で使用された値ReserveDicシートに記載された定義文字列の中に$arg1、$arg2...があれば、x,y,...に置き換えられます。($argはFTの予約語です。1,2,...は位置を示します)

※ マクロ名は可読性を重視し、一目で理解できるように命名するとよいでしょう。

※ Javaソースを編集する際に使用できる構文はJavassistに準拠しています。Javassistのマニュアルを一読することをお勧めします。

主な留意点としては、

  • クラスはFQN(Fully Qualified Name)を使用する。

  • Genericは使わない。「<?>」を外して使う。

などがあります。

5.2.4. 複数の属性にまたがる処理を設定するための準備

ある属性値を設定するコードで、別の属性を参照したり設定したりする場合があります。 他の属性にアクセスするためには、最初に「field」宣言をする必要があります。

属性にm_cawとm_printWiterがある場合のm_printWriterの生成コード

field java.io.CharArrayWriter m_caw=new java.io.CharArrayWriter(); return new java.io.PrintWriter(m_caw);

この例は、HttpServletResponseのgetWriterのスタブ実装例です。m_printWriterの設定値を生成する際に、CharArrayWriterを属性値に設定しつつ、PrintWriterを生成する処理です。 「field」宣言はFT独自の構文です。これにより、一時的に引数オブジェクトの属性「m_caw」へのアクセスが可能となっています。

※ 上記の例は宣言と同時に値を設定していますが、宣言だけでもOKです。

5.2.5. 実行時評価文字列の埋め込み

Web画面のテストと同様に、文字列に埋め込めるJava関数を設定することができます。 日付の指定などに使用するとよいでしょう。

5.3. クラスもしくはインタフェースのスタブを作成する

多くのサーバ基盤ソフトウェアにおいて、アプリケーションが必要な最小限の情報をインタフェースとして渡すというデザインパターンが採用されています。例えば、HttpServletのdoPostに渡される、ServletRequestやServletResponseなどのインタフェースです。

このデザインパターンは、アプリケーションを基盤ソフトウェアに依存させ過ぎないようにするメリットがありますが、プログラムによる単体テストおよび付随するデバッグ作業を難しくするものでした。引数として渡されてくるオブジェクトの内部仕様が不明なために、正しく実装されているかよくわからないスタブを作らねばなりません。また、デバッグにおいては、Eclipseなどで開発者が自身のコードの中にブレークポイントを設定し、状態を確認ながら、処理をトレースしていくことが、日常的に行われています。従って、テストプログラムで検出した障害の調査の際に、該当のプログラムを動かしながらデバッグしたくなるものです。しかし、そのためには十分に実装したスタブを作る必要がありました。本ツールでは、半自動的に、必要な部分だけのスタブを作る仕組みを提供しています。

「Javaアプリケーションのテスト作成」編の「スタブを作成する」手順に従い、オブジェクトをスタブに指定します。 クイックアクセスメニューの「テストを実行する」を選択する際に、shiftキーを押下することにより、スタブを編集するモードでテスト実行することができます。

5.3.1. スタブのSetter、Getterのデフォルト処理

スタブの元クラスがpublicなsetterもしくはgetterを宣言していた場合、FTはそのメソッド名から自動的にスタブ用のメンバ変数を作成します。setterの場合、スタブ用のメンバ変数を設定する処理を行い、getterの場合、スタブ用メンバ変数をそのまま返却します。 スタブ用メンバ変数の名前は、メソッド名からsetもしくはgetを除去し、先頭を小文字に変え、さらに冠に「m_」を付けたものです。

スタブ用メンバ変数の値は、JsonPathにより設定することができます。

※ これができるのは、比較的単純なオブジェクトに限られます。それ以外の場合、「スタブメソッドを編集する」のように、テスト対象のプログラムから呼ばれるスタブのメソッド処理を編集する必要があります。このメソッドが標準的に使用されるのであれば、アーキテクトが編集し、標準化した方がプロジェクトの運用がスムーズになるでしょう。

※ getterがキーとなる引数を持つ場合には、スタブ用メンバ変数としてMap属性を生成します。

5.3.2. スタブメソッドの処理を自由に編集する

スタブメソッドの処理内容を自由に記述するには、スタブクラスを引数に使用しているTestSuiteシートを開き、shiftキーを押下しながら、クイックアクセスツールバーの「テストを実行する」を選択します。

../_images/stubeditor.png

テスト対象のプログラムの中で、直接もしくは間接的にスタブのメソッドをコールすると、そのメソッドの処理を編集するエディタが開きます。

エディタの左上部には、返却値、引数、フィールドの内容が表示されます。右上部には、スタブメソッドが呼び出されるまでのコールスタックが表示されます。

エディタの下部のテキストエリアでメソッドの処理を作成・編集することができます。 また、次のようなマクロ関数が使用できます。

VGET(String "$n.属性...") //$n.属性:スタブメソッドのn番目の引数の属性をJsonPathで指定します.

VSET(Object obj, String"属性名", Object fieldObj)

MOCK(String "クラス名", String "フィールド名=識別文字列")

VGET()はobject(メソッドの引数と返却値に限定される)と引数の属性をJsonPath的に指定し、その属性値を取得します。

VSET()は第一引数のオブジェクト(引数のオブジェクトもしくはMOCKマクロで作成したスタブオブジェクト)に対して、引数2で指定した属性の値を、引数3により設定します

MOCK()は、変数のinitializeの処理や、スタブの中で別のスタブクラスを生成する必要がある場合に使用し、指定したクラスのスタブを返却します。そのスタブが未作成の場合、クラスファイルを自動生成します。第二引数の文字列は同じクラスのスタブを複数使用する場合のためのものです。文字列の書式は、

フィールド名=識別文字列

です。識別文字列には呼び出されたケースごとに、フィールド名(スタブクラスの静的なメンバ変数)に割り当てます。このスタブインスタンスの中で、静的なフィールド名にアクセスすることにより、どのケースなのかを識別し、ケースに依存した処理を行うことができます。 また、MOCKを使用するに当たって、引数はすべて文字列と見なしますので、""は不要です。

※ 注意:作成したスタブクラスは、FTのDBで共有されるため、スタブのメソッドの定義の中で、ケースに依存した処理を記述することができます。

また、メソッドの処理の中で、

field クラス名のFQN 変数名;

を宣言すると、FT独自のプリプロセッサにより、その変数をスタブオブジェクトのFieldとして扱うことができます。従って、setter、getterに対応する属性を設定したり、参照することも容易になります。setter、getterなどデフォルトで作成されていない変数に「field」宣言した場合、その変数はメンバ変数として追加されます。

スタブクラスをデータベースに保存すると、メソッドのテストを行うExcelシートにおいて、JsonPathにより、実行前に変数の値を外部から設定したり、実行後の検証のために参照することができます。

※ Javaソースを編集する際に使用できる構文はJavassistに準拠しています。Javassistのマニュアルを一読することをお勧めします。

  • メソッドの引数にアクセスするためには、$1,$2,...というシンボルを使用します。

5.4. includeするTestSuite

実際のテスト処理の前に処理を行いたい場合があります。例えば、スタブから参照されえる大域変数の設定、既存のクラスのメソッドをスタブ化するための改変などです。、 それらの処理をあらかじめTestSuiteとしてデータベースに登録しておくと、開発者はそれらをincludeして利用することができます。

また、複数のTestSuiteをincludeすることもできます。

5.4.1. 第三者作成クラスの改変

OSSなどの共通ライブラリなど第三者が作成したクラスメソッドをメモリ上で書き替え、あたかもスタブのように扱うことができます。

例えば、DBアクセスオブジェクトをネーミングサービスのような標準DI(依存性の注入)機能を利用しているプログラムでは、環境設定やAPIにより、特定のクラスをテスト用の別クラスに差し替えることができます。但し、このためにはネーミングサービスなどの実行の環境を構築する必要があったり、あるいはAPIで名前とオブジェクトをバインドするプログラムを作成したり手間がかかります。

その他にも、OSSや他のベンダーが作ったクラスを使用している場合に、その環境設定を行うには単体テストの環境ではできなかったりすることがあります。そのような場合、既それらクラスのメソッドをメモリ上で動的に変更することにより、単体テストをより簡単に行える場合があります。

  1. JavaメソッドをテストするためのExcelに、第三者が作成したクラスおよびスタブ化したいメソッドを指定して、テスト用シートを作成します。

  2. メソッド名の末尾に「?」を付加します。

  3. ReservedDicシートに次のような行を記述します。

A列

B列

シート名.source

メソッドの処理を上書きするためのJavaソース

  1. データベースに保存し、一般の開発者にTestSuite名を公開します。

  2. 一般開発者は、includeするTestSuiteとして、4で作成したTestSuiteを指定すると、そのクラスメソッドの内部処理を置き換えた形で使用できるようになります。

※ 4で作成したTestSuiteにおいて検証を設定する必要はありません。

※ スタブと同様に「field」宣言を行うことにより、そのオブジェクトの属性に直接アクセスすることができます。

※ 注意:Java実行系が保護しているクラスメソッドについては改変することができません。

※ Javaソースを編集する際に使用できる構文はJavassistに準拠しています。Javassistのマニュアルを一読することをお勧めします。

5.5. I18N

必要に応じて、JavaTestTemplate.xlmsのLiteralDicシートを加筆修正します。