3.1.1.1. Form/Entityのクラス単体テスト

本項では、FormおよびFormの一種であるEntityのクラス単体テスト(以下Form単体テストまたはEntity単体テスト)について説明する。 両者はほぼ同じように単体テストを行えるため、共通する内容についてはEntity単体テストをベースに説明し、特有の処理については個別に説明する。

補足

Entityとは、テーブルのカラムと1対1に対応するプロパティを持つFormのことである。

3.1.1.1.1. Form/Entity単体テストの書き方

本項で例として使用したテストクラスとテストデータは以下のとおり(右クリック->保存でダウンロード)。

3.1.1.1.1.1. テストデータの作成

テストデータを記載したExcelファイルそのものの作成方法を説明する。テストデータを記載したExcelファイルは、テストソースコードと同じディレクトリに同じ名前で格納する(拡張子のみ異なる)。なお、後述する精査のテストケースコンストラクタのテストケースsetter、getterに対するテストケースのそれぞれが、1シートずつ使用する前提である。

テストデータの記述方法詳細については、自動テストフレームワークデータベースを使用するクラスのテストを参照。

なお、メッセージデータやコードマスタなどの、データベースに格納する静的マスタデータは、プロジェクトで管理されたデータがあらかじめ投入されている(これらのデータを個別のテストデータとして作成しない)前提である。

3.1.1.1.1.2. テストクラスの作成

Form/Entity単体テストのテストクラスは、以下の条件を満たすように作成する。

  • テストクラスのパッケージは、テスト対象のForm/Entityと同じとする。
  • <Form/Entityクラス名>Testというクラス名でテストクラスを作成する。
  • nablarch.test.core.db.EntityTestSupportを継承する。
package nablarch.sample.management.user; // 【説明】パッケージはSystemAccountEntityと同じ

import java.util.HashMap;
import java.util.Map;

import org.junit.Test;

import nablarch.test.core.db.EntityTestSupport;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;

/**
 * SystemAccountEntityクラスに対するテストを実行するクラス。<br/>
 * テスト内容はエクセルシート参照のこと。
 *
 * @author Miki Habu
 * @since 1.0
 */
public class SystemAccountEntityTest extends EntityTestSupport {
// 【説明】クラス名はSystemAccountEntityTestで、EntityTestSupportを継承する


// ~後略~

テストメソッドの記述方法は本項以降に記載されているコード例を参照。

3.1.1.1.1.3. 文字種と文字列長の単項目精査テストケース

単項目精査に関するテストケースは、入力される文字種および文字列長に関するものがほとんどである。例えば、以下のようなプロパティがあるとする。

  • プロパティ名「フリガナ」
  • 最大文字列長は50文字
  • 必須項目
  • 全角カタカナのみを許容する

この場合、以下のようなテストケースを作成することになる。

ケース 観点
全角カタカナ50文字を入力し精査が成功する。 最大文字列長、文字種の確認
全角カタカナ51文字を入力し精査が失敗する。 最大文字列長の確認
全角カタカナ1文字を入力し精査が成功する。 最小文字列長、文字種の確認
空文字を入力し、精査が失敗する。 必須精査の確認
半角カタカナを入力し精査が失敗する。 文字種の確認[1]

[1]同様に、半角英字、全角ひらがな、漢字...等が入力され精査が失敗するケースが必要である。

このように、単項目精査のテストケースは、ケース数が多くなりデータ作成の労力がかかる。そこで、単項目精査テスト専用のテスト方法を提供する。これにより以下の効果が見込まれる。

  • 単項目精査のテストケース作成を容易になる。
  • 保守性の高いテストデータが作成でき、レビューやメンテナンスが容易になる。

補足

本テスト方法は、プロパティとして別のFormを保持するFormに対しては使用できない。その場合、独自に精査処理のテストを実装すること。 プロパティとして別のFormを保持するFormとは、以下の形式でプロパティにアクセスする親Formのこと。

<親Form>.<子Form>.<子フォームのプロパティ名>

3.1.1.1.1.3.1. テストケース表の作成方法

以下のカラムを用意する。

カラム名 記載内容
propertyName テスト対象のプロパティ名
allowEmpty そのプロパティが未入力を許容するか
min そのプロパティが入力値として許容する最小文字列長( 省略可)
max そのプロパティが入力値として許容する最大文字列長
messageIdWhenNotApplicable 文字種不適合時に期待するメッセージID
半角英字 半角英字を許容するか
半角数字 半角数字を許容するか
半角記号 半角記号を許容するか
半角カナ 半角カナを許容するか
全角英字 全角英字を許容するか
全角数字 全角数字を許容するか
全角ひらがな 全角ひらがなを許容するか
全角カタカナ 全角カタカナを許容するか
全角漢字 全角漢字を許容するか
全角記号その他 全角記号その他を許容するか
外字 外字を許容するか

許容するかどうかを記入するカラムには、以下の値を設定する。

設定内容 設定値 備考
許容する o 半角英小文字のオー
許容しない x 半角英小文字のエックス

具体例を以下に示す。

../../../../../../_images/entityUnitTest_CharsetAndLengthExample.png

3.1.1.1.1.3.2. テストメソッドの作成方法

スーパクラスの以下のメソッドを起動する。

void testValidateCharsetAndLength(Class entityClass, String sheetName, String id)

 // 【説明】~前略~

public class SystemAccountEntityTest extends EntityTestSupport {

     /** テスト対象エンティティクラス */
     private static final Class<SystemAccountEntity> ENTITY_CLASS = SystemAccountEntity.class;


     /**
      * 文字種および文字列長のテストケース
      */
     @Test
     public void testCharsetAndLength() {
          // 【説明】テストデータを記載したシート名
          String sheetName = "testCharsetAndLength";

          // 【説明】テストデータのID
          String id = "charsetAndLength";

          // 【説明】テスト実行
          testValidateCharsetAndLength(ENTITY_CLASS, sheetName, id);
     }


     // 【説明】~後略~

このメソッドを実行すると、テストデータの各行毎に以下の観点でテストが実行される。

観点 入力値 備考
文字種 半角英字 max(最大文字列長)欄に記載した長さの文字列で構成さ れる。
文字種 半角数字
文字種 半角数字
文字種 半角記号
文字種 半角カナ
文字種 全角英字
文字種 全角数字
文字種 全角ひらがな
文字種 全角カタカナ
文字種 全角漢字
文字種 全角記号その他
文字種 外字
未入力 空文字 長さ0の文字列
最小文字列 最小文字列長の文字列 入力値は、o印を付けた文字種で構成される
最長文字列 最長文字列長の文字列
文字列長不足 最小文字列長-1の文字列
文字列長超過 最大文字列長+1の文字列

3.1.1.1.1.4. その他の単項目精査のテストケース

前述の、文字種と文字列長の単項目精査テストケースを使用すれば大部分の単項目精査がテストできるが、一部の精査についてはカバーできないものもある。 例えば、数値入力項目の範囲精査が挙げられる。

このような単項目精査のテストについても、簡易にテストできる仕組みを用意している。 各プロパティについて、1つの入力値と期待するメッセージIDのペアを記述することで、 任意の値で単項目精査のテストができる。

補足

本テスト方法は、プロパティとして別のFormを保持するFormに対しては使用できない。その場合は、独自に精査処理のテストを実装すること。 プロパティとして別のFormを保持するFormとは、以下の形式でプロパティにアクセスする親Formのこと。

<親Form>.<子Form>.<子フォームのプロパティ名>

3.1.1.1.1.4.1. テストケース表の作成方法

以下のカラムを用意する。

カラム名 記載内容
propertyName テスト対象のプロパティ名
case テストケースの簡単な説明
input1[2] 入力値 [3]
messageId 上記入力値で単項目精査した場合に、発生すると期待す るメッセージID(精査エラーにならないことを期待する 場合は空欄)
[2]ひとつのキーに対して複数のパラメータを指定する場合は、input2, input3 というようにカラムを増やす。

[3]セルへの特殊な記述方法の記法を使用することで、効率的に入力値を作成できる。

具体例を以下に示す。

../../../../../../_images/entityUnitTest_singleValidationDataExample.png

3.1.1.1.1.4.2. テストメソッドの作成方法

スーパクラスの以下のメソッドを起動する。

void testSingleValidation(Class entityClass, String sheetName, String id)
// 【説明】~前略~

public class SystemAccountEntityTest extends EntityTestSupport {

     /** テスト対象エンティティクラス */
     private static final Class<SystemAccountEntity> ENTITY_CLASS = SystemAccountEntity.class;

     /**
      * 文字種および文字列長の単項目精査テストケース
      */
     // 【説明】~中略~

     /**
      * 単項目精査のテストケース(上記以外)
      */
     @Test
     public void testSingleValidation() {
         String sheetName = "testSingleValidation";
         String id = "singleValidation";
         testSingleValidation(ENTITY_CLASS, sheetName, id);
     }


      // 【説明】~後略~

3.1.1.1.1.5. バリデーションメソッドのテストケース

上記までの単項目精査のテストでは、エンティティのセッターメソッドに付与されたアノテーションが正しいかテストされ、エンティティに実装したバリデーションメソッド[4]は実行されていない。

その為、独自のバリデーションメソッドをエンティティに実装した場合は、 別途テストを作成する必要がある。

[4]@ValidateForアノテーションを付与したstaticメソッドのこと

3.1.1.1.1.5.1. テストケース表の作成

  • IDは”testShots”固定とする。
  • 以下のカラムを用意する。
カラム名 記載内容
title テストケースのタイトル
description テストケースの簡単な説明
expectedMessageId 期待するメッセージ(は1からの連番 )
propertyName 期待するプロパティ(は1からの連番 )

複数のメッセージを期待する場合、expectedMessageId2, propertyName2というように数値を増やして右側に追加していく。

  • 入力パラメータ表の作成
    • IDは”params”固定とする。
    • 上記のテストケース表に対応する、入力パラメータ[5] を1行ずつ記載する。

[5]セルへの特殊な記述方法の記法を使用することで、効率的に入力値を作成できる。

具体例を以下に示す。

../../../../../../_images/entityUnitTest_validationTestData.png

※Entityの保有するプロパティ名のExcelへの記述手順は、 プロパティ名の一覧を簡易的に取得する手順 を参照。

3.1.1.1.1.5.2. テストケース、テストデータの作成

3.1.1.1.1.5.2.1. 精査対象確認

精査対象のプロパティを指定(Nablarch Validation参照)した場合、その指定が正しいかどうか確認するケースを作成する。

全てのプロパティに対して、おのおの単項目精査でエラーとなるデータを用意する。精査対象プロパティの指定が正しければ、精査対象のプロパティだけが単項目精査になるはずである。よって、期待値として、全精査対象プロパティ名と、各プロパティ単項目精査エラー時のメッセージIDを記載する。

補足

精査対象プロパティが誤って精査対象から漏れていた場合、期待したメッセージが出力されない為、メッセージIDのアサートが失敗する。また、精査対象でないプロパティが誤って精査対象となっていた場合は、入力値が不正により単項目精査が失敗し、予期しないメッセージが出力される。これにより、精査対象の誤りを検知することができる。

テストケース表には、全精査対象プロパティのプロパティ名と、そのプロパティ単項目精査エラーメッセージIDを記載する。

../../../../../../_images/entityUnitTest_ValidationPropTestCases.png

入力パラメータ表には、全てのプロパティに対してそれぞれ単項目精査エラーとなる値を記載する。

../../../../../../_images/entityUnitTest_ValidationPropParams.png

補足

Form単体テストのテストケースやテストデータを作成する際、プロパティに保持している別のFormのプロパティ を指定したいことがある。この場合、次のように指定できる。

  • Formのコード例
public class SampleForm {

    /** システムユーザ */
    private SystemUserEntity systemUser;

    /** 電話番号配列 */
    private UserTelEntity[] userTelArray;

    // 【説明】プロパティ以外は省略

}
  • 保持しているFormのプロパティを指定する方法(SystemUserEntity.userIdを指定する場合)
sampleForm.systemUser.userId
  • Form配列の要素のプロパティを指定する方法(UserTelEntity配列の先頭要素のプロパティを指定する場合)
sampleForm.userTelArray[0].telNoArea
3.1.1.1.1.5.2.2. 項目間精査など

項目間精査など、バリデーションメソッドの精査対象確認で行った精査対象指定以外の動作確認を行うケースを作成する。

下図では、”newPasswordとconfirmPasswordが等しいこと”というバリデーションメソッドに対する正常系のケースを作成している。

../../../../../../_images/entityUnitTest_RelationalValidation.png

3.1.1.1.1.5.3. テストメソッドの作成方法

これまでに作成したテストケース、データを使用するテストメソッドを以下に示す。下記コードの変数内容を変更するだけで、異なるEntityの精査のテストに対応できる。

 // ~前略~

 /** テスト対象エンティティクラス */
 private static final Class<SystemAccountEntity> ENTITY_CLASS = SystemAccountEntity.class;

 // ~中略~
 /**
  * {@link SystemAccountEntity#validateForRegisterUser(nablarch.core.validation.ValidationContext)} のテスト。
  */
 @Test
 public void testValidateForRegisterUser() {
     // 精査実行
     String sheetName = "testValidateForRegisterUser";
     String validateFor = "registerUser";
     testValidateAndConvert(ENTITY_CLASS, sheetName, validateFor);
 }

// ~後略~

3.1.1.1.1.6. コンストラクタに対するテストケース

コンストラクタに対するテストでは、引数に指定した値が、正しくプロパティに設定されているかを確認するケースを作成する。このとき対象となるプロパティは、Entityにに定義されている全てのプロパティである。テストデータには、プロパティ名とそれに設定するデータと期待値(getterで取得した値と比較するデータ)を用意する。

下図では、以下のように各プロパティに値を指定している。 テストでは、コンストラクタにこれらの値の組み合わせを与えたとき、各プロパティに指定した値が設定されているか(getterを呼び出して、想定通りの値が取得できるか)確認している。

実際のテストコードでは、コンストラクタへの値の設定及び値の確認は、自動テストフレームワークで提供されるメソッド内で行われる。 詳細は、 テストコード を参照すること。

補足

Entityは自動生成されるため、アプリケーションで使用されないコンストラクタが生成される可能性がある。その場合リクエスト単体テストではテストできないため、Entity単体テストでコンストラクタに対するテストを必ず行うこと。

一方、一般的なFormの場合、アプリケーションで使用するコンストラクタのみを作成する。したがって、リクエスト単体テストでコンストラクタのテストを行うことができる。そのため、一般的なFormについては、クラス単体テストでコンストラクタのテストを行う必要はない。

3.1.1.1.1.6.1. Excelへの定義

../../../../../../_images/entityUnitTest_Constructor.png

※Entityの保有するプロパティ名のExcelへの記述手順は、 プロパティ名の一覧を簡易的に取得する手順 を参照。

上記設定値のテスト内容(抜粋)

プロパティ コンストラクタに設定する値 期待値(getterから取得される値
userId userid userid
loginId loginid loginid
password password password

このデータを使用するテストメソッドを以下に示す。

// 【説明】~前略~

public class SystemAccountEntityTest extends EntityTestSupport {

     /** コンストラクタのテスト */
     @Test
     public void testConstructor() {
         Class<?> entityClass = SystemAccountEntity.class;
         String sheetName = "testAccessor";
         String id = "testConstructor";
         testConstructorAndGetter(entityClass, sheetName, id);
     }

}

補足

testConstructorAndGetterでテスト可能なプロパティの型(クラス)には制限がある。 下記型(クラス)に該当しない場合には、各テストクラスにてコンストラクタとgetterを明示的に呼び出してテストする必要がある。

  • String及び、String配列
  • BigDecimal及び、BigDecimal配列
  • java.util.Date及び、java.util.Date配列(Excelへはyyyy-MM-dd形式もしくはyyyy-MM-dd HH:mm:ss形式で記述すること)
  • valueOf(String)メソッドを持つクラス及び、その配列クラス(例えばIntegerやLong、java.sql.Dateやjava.sql.Timestampなど)

以下に、個別のテスト実施方法の例を示す。

  • Excelへのデータ記述例

    ../../../../../../_images/entityUnitTest_ConstructorOther.png
  • テストコード例

    /** コンストラクタのテスト */
    @Test
    public void testConstructor() {
        // 【説明】
        // 共通にテストが実施出来る項目は、testConstructorAndGetterを使用してテストを実施する。
        Class<?> entityClass = SystemAccountEntity.class;
        String sheetName = "testAccessor";
        String id = "testConstructor";
        testConstructorAndGetter(entityClass, sheetName, id);
    
        // 【説明】
        // 共通にテストが実施出来ない項目は、個別にテストを実施する。
    
        // 【説明】
        // getParamMapを呼び出し、個別にテストを行うプロパティのテストデータを取得する。
        // (テスト対象のプロパティが複数ある場合は、getListParamMapを使用する。)
        Map<String, String[]> data = getParamMap(sheetName, "testConstructorOther");
    
        // 【説明】Map<String, String[]>から、Entityのコンストラクタの引数であるMap<String, Object>へ変換する
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("users", Arrays.asList(data.get("set")));
    
        // 【説明】上記で生成したMap<String, Object>を引数にEntityを生成する。
        SystemAccountEntity entity = new SystemAccountEntity(params);
    
        // 【説明】getterを呼び出し、期待値通りの値が返却されることを確認する。
        assertEquals(entity.getUsers(), Arrays.asList(data.get("get")));
    
    }
    

3.1.1.1.1.7. setter、getterに対するテストケース

setter、getterに対するテストでは、setterで設定した値とgetterで取得した値が、期待通りになっているか確認するケースを作成する。このとき対象となるプロパティは、Entityに定義されている全てのプロパティである。

各プロパティに対して、setterに渡すためのデータと期待値(getterで取得した値と比較するデータ)を用意する。 テストメソッドでは、前述のsetterに渡すためのデータを引数にsetterを呼び出し、直後にgetterで取得した値と期待値が等しいことを確認している。

実際のテストコードでは、setterへの値の設定及び値の確認(期待値との比較)は、 自動テストフレームワークで提供されるメソッド内で行われる。 詳細は、 テストコード を参照すること。

補足

Entityは自動生成されるため、アプリケーションで使用されないsetter/getterが生成される可能性がある。その場合リクエスト単体テストではテストできないため、Entity単体テストでsetter/getterに対するテストを必ず行うこと。

一方、一般的なFormの場合、アプリケーションで使用するsetter/getterのみを作成する。したがって、リクエスト単体テストでsetter/getterのテストを行うことができる。そのため、一般的なFormについては、クラス単体テストでsetter/getterのテストを行う必要はない。

3.1.1.1.1.7.1. Excelへの定義

../../../../../../_images/entityUnitTest_SetterAndGetter.png

※Entityの保有するプロパティ名のExcelへの記述手順は、 プロパティ名の一覧を簡易的に取得する手順 を参照。

このデータを使用するテストメソッドを以下に示す。

// 【説明】~前略~

public class SystemAccountEntityTest extends EntityTestSupport {

    /**
     * setter、getterのテスト
     */
    @Test
    public void testSetterAndGetter() {
        Class<?> entityClass = SystemAccountEntity.class;
        String sheetName = "testAccessor";
        String id = "testGetterAndSetter";
        testSetterAndGetter(entityClass, sheetName, id);
    }

    // 【説明】~後略~

補足

testGetterAndSetterでテスト可能なプロパティの型(クラス)には制限がある。 制限内容の詳細は、 コンストラクタに対するテストケース を参照すること。

補足

setterやgetterにロジックを記述した場合(例えば、setterは郵便番号上3桁と下4桁に別れているが、getterはまとめて7桁取得する場合など)は、 そのロジックを確認するテストケースを作成すること。

上記のテストをExcelに定義する場合には、下記画像のように定義する。:

郵便番号に下記を設定した場合に、正しく7桁の郵便番号(0010001)が取得することを確認する例
  郵便番号上3桁:001
  郵便番号下4桁:0001
../../../../../../_images/entityUnitTest_SetterAndGetter_PostNo.png

3.1.1.1.1.8. プロパティ名の一覧を簡易的に取得する手順

①Eclipseでテスト対象のEntityクラスをオープンし、Outline(アウトライン)を表示する。

../../../../../../_images/entityUnitTest_PropertyWrite1.png

②コピーしたいプロパティを選択する。

../../../../../../_images/entityUnitTest_PropertyWrite2.png

③マウスの右クリックで表示されるメニューからCopy Qualified Name(修飾名のコピー)を選択する。

../../../../../../_images/entityUnitTest_PropertyWrite3.png

④コピーしたプロパティ名のリストをエクセルに貼り付ける。

貼りつけた値には、下記画像のように「クラス名 + プロパティ名」の完全修飾名の形式になっている。 このため、Excelの置き換え機能を使用して不要なクラス名を削除する。

Entityクラスが、「nablarch.sample.management.user.SystemAccountEntity」の場合の置き換え例:

検索する文字列:nablarch.sample.management.user.SystemAccountEntity.
置き換え後の文字列:(空のまま)
../../../../../../_images/entityUnitTest_PropertyWrite4.png

3.1.1.1.1.9. 自動テストフレームワーク設定値

文字種と文字列長の単項目精査テストケースを実施する際に必要な初期値設定について説明する。

3.1.1.1.1.9.1. 設定項目一覧

nablarch.test.core.entity.EntityTestConfigurationクラスを使用し、以下の値をコンポーネント設定ファイルで設定する(全項目必須)。

設定項目名 説明
maxMessageId 最大文字列長超過時のメッセージID
maxAndMinMessageId 最長最小文字列長範囲外のメッセージID(可変長)
fixLengthMessageId 最長最小文字列長範囲外のメッセージID(固定長)
underLimitMessageId 文字列長不足時のメッセージID
emptyInputMessageId 未入力時のメッセージID
characterGenerator 文字列生成クラス [6]

[6]nablarch.test.core.util.generator.CharacterGeneratorの実装クラスを指定する。 このクラスがテスト用の入力値を生成する。 通常は、nablarch.test.core.util.generator.BasicJapaneseCharacterGeneratorを使用すれば良い。

設定するメッセージIDは、バリデータの設定値と合致させる。

(以下の記述例を参照)

3.1.1.1.1.9.2. コンポーネント設定ファイルの記述例

以下の設定値を使用する場合のコンポーネント設定ファイル記述例を示す。

【精査クラスのコンポーネント設定ファイル】

<property name="validators">
  <list>
    <component class="nablarch.core.validation.validator.RequiredValidator">
      <property name="messageId" value="MSG00010"/>
    </component>
    <component class="nablarch.core.validation.validator.LengthValidator">
      <property name="maxMessageId" value="MSG00011"/>
      <property name="maxAndMinMessageId" value="MSG00011"/>
      <property name="fixLengthMessageId" value="MSG00023"/>
    </component>
    <!-- 中略 -->
</property>

【テストのコンポーネント設定ファイル】

<!-- エンティティテスト設定 -->
<component name="entityTestConfiguration" class="nablarch.test.core.entity.EntityTestConfiguration">
  <property name="maxMessageId"        value="MSG00011"/>
  <property name="maxAndMinMessageId"  value="MSG00011"/>
  <property name="fixLengthMessageId"  value="MSG00023"/>
  <property name="underLimitMessageId" value="MSG00011"/>
  <property name="emptyInputMessageId" value="MSG00010"/>
  <property name="characterGenerator">
    <component name="characterGenerator"
               class="nablarch.test.core.util.generator.BasicJapaneseCharacterGenerator"/>
  </property>
</component>