10.2.1. テストの事前準備

本節では単体テストを実施するための事前準備として、利用するOSSライブラリの設定方法とデータセットアップ方法および テスト実装例で使用する設定ファイルについて説明する。

10.2.1.1. OSSライブラリの設定

単体テストを実行するプロジェクト(domainプロジェクト、webプロジェクト)のPOMファイルにテストで利用するOSSライブラリを設定する。

  • pom.xml

<!-- == Begin Database == -->
<!-- <dependency> -->
<!-- <groupId>org.postgresql</groupId> -->
<!-- <artifactId>postgresql</artifactId> -->
<!-- <scope>test</scope> -->
<!-- </dependency> -->
<!-- == End Database == -->

<!-- == Begin Unit Test == -->
<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>org.mockito</groupId>
  <artifactId>mockito-core</artifactId>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-test</artifactId>
  <scope>test</scope>
</dependency>
<!--  REMOVE THIS LINE IF YOU USE DBUnit
<dependency>
  <groupId>org.dbunit</groupId>
  <artifactId>dbunit</artifactId>
  <version>2.7.2</version>
  <scope>test</scope>
</dependency>
-->
<!--  REMOVE THIS LINE IF YOU USE Spring Test DBUnit
<dependency>
  <groupId>com.github.springtestdbunit</groupId>
  <artifactId>spring-test-dbunit</artifactId>
  <version>1.3.0</version>
  <scope>test</scope>
</dependency>
-->
<!-- == End Unit Test == -->

Note

dbunitspring-test-dbunit以外の上記設定例は、依存ライブラリのバージョンを親プロジェクトである terasoluna-gfw-parentで管理する前提であるため、pom.xmlでのバージョン指定は不要である。 また、hamcrestについては、junitが依存関係を解決しているため、改めて定義する必要はない。

Tip

PostgreSQLドライバの追加方法について

データアクセスを伴うテストでPostgreSQLのドライバを使用する場合は、POMファイル内のPostgreSQLのドライバのコメントアウトを外すこと。 なお、テストのために依存ライブラリが必要になる場合のスコープはtestが適切である。

10.2.1.2. データベースのセットアップ

10.2.1.2.1. スキーマとテストデータのセットアップ(Spring Test標準機能のみを利用したテストの場合)

単体テストで利用するデータベースのセットアップについて、以下の方法がある。

セットアップ方法

特徴

利用シーン

<jdbc:initialize-database>要素を使用する。
<jdbc:initialize-database>要素を定義した設定ファイルをテスト実施時に読み込みセットアップする。
インメモリデータベース(H2 Database)をセットアップする際に使用する。
initdbプロジェクトを使用する。
テスト実施と分離して事前にDBの初期化ができる。
テスト実施前にまとめてデータベースをセットアップする際に使用する。
@org.springframework.test.context.jdbc.Sqlアノテーションを使用する。
@Sqlアノテーションの引数で指定したSQLを発行する。 @Sqlアノテーションはメソッドレベル、クラスレベルで指定できる。 メソッドレベルで指定した場合は指定したテストメソッドだけで、 クラスレベルで指定した場合は@Sqlアノテーションの指定がないすべてのテストメソッドで、 実行前後にSQLを発行できる。
テストごとにテストデータをセットアップする際に使用する。

Warning

<jdbc:initialize-database>タグに設定するSQLファイルには、明示的に「COMMIT;」を記述すること。

単体テストで利用するスキーマのセットアップは、テストごとではなくテスト実施前にまとめて実施されることが想定される。 そのため、本章ではテストと分離したinitdbプロジェクトを使用してスキーマを作成することを前提に説明する。 initdbプロジェクトについては、initdbモジュールの構成を参照されたい。

一方、テストデータのセットアップはテストごとに実施されることが想定される。 そのため、本章ではテストクラスまたはテストメソッド毎にSQLを発行できる@Sqlアノテーションを使用することを前提に説明する。

以下に、メソッドレベルに@Sqlアノテーションを付与する場合のテストデータのセットアップ例を示す。

  • MemberRepositoryTest.java

public class MemberRepositoryTest {

@Test
@Sql(scripts = "classpath:META-INF/sql/setupMemberLogin.sql" // (1)
     config = @SqlConfig(encoding = "utf-8")) // (2)
public void testUpdateMemberLogin() {
    // omitted
}

項番

説明

(1)
@Sqlアノテーションに、テストに必要なデータを投入するSQLファイルを指定する。
(2)
@SqlConfigアノテーションを使用してSQLファイルのエンコードを指定する。

Tip

@Sqlについて

@Sqlアノテーションの引数には、以下を指定できる。

  • SQLファイル(scriptsまたは value

  • SQLステートメント(statements

  • SQL実行フェイズ(executionPhase

  • SQL解析メタデータ(config@SqlConfigアノテーションを指定)

また、@Sqlアノテーションはデフォルトで有効になっているSqlScriptsTestExecutionListenerによって 実行される。詳細は、Executing SQL scripts declaratively with @Sqlを参照されたい。

なお、@Sqlアノテーションと@SqlConfigアノテーションによる構成は<jdbc:initialize-database>要素 による構成の上位セットである。

Note

@SqlのSQLファイルパスの省略

@Sqlアノテーションは、@ContextConfigurationアノテーション同様、SQLファイルのパスを省略でき、 省略した場合@Sqlアノテーションが指定された場所に基づいてSQLファイルの検索が行われる。

例えば、以下のようにデフォルトのパスにあるファイルがロードされる。

com.example.domain.repository.SampleRepositoryTestに指定した場合 → classpath:com/example/domain/repository/SampleRepositoryTest.sql

SampleRepositoryTest#testUpdate()に指定した場合 → classpath:com/example/domain/repository/SampleRepositoryTest.testUpdate.sql

なお、デフォルトのパスを検出できない場合は、java.lang.IllegalStateExceptionがthrowされる。

Note

@Sqlの複数指定

@SqlにはJava SE8から追加された@Repeatableが付与されているため、同じ箇所に複数指定することができる。 なお、@org.springframework.test.context.jdbc.SqlGroupを使用して、@Sqlを配列で複数指定することも可能である。

10.2.1.2.2. テストデータのセットアップ(Spring Test DBUnitを利用したテスト場合)

DBUnitとは、データベースに依存するクラスのテストを行うためのJUnit拡張フレームワークである。 DBUnitとSpring Test DBUnitを使用して、テスト用データベースをセットアップする方法を説明する。

DBUnitは、表形式で記載したデータベース情報をJavaオブジェクトとして抽象化して操作するための org.dbunit.dataset.IDataSetインタフェースを提供している。 IDataSetインタフェースを使用することで、テストデータや期待結果データを定義したデータ定義ファイルを読み込むことができ、 デフォルトではFlat XML形式のファイルが使用される。 DBUnitはFlat XML形式の他に、Excel形式(.xlsx)やCSV形式などに対応したIDataSetインタフェースの実装クラスを持つ。

Spring Test DBUnitではデータ定義ファイルの読込機能をcom.github.springtestdbunit.dataset.DataSetLoaderインタフェースの実装クラスに委譲している。デフォルトではXML形式のデータ定義ファイルが読み込まれる。 ファイル形式を変更したい場合は、変更したい形式に対応したIDataSetインタフェースの実装クラスを生成する DataSetLoaderインタフェースの実装クラスを作成することで実現できる。

なお、Spring Test DBUnitを使用してデータのセットアップをする場合は、@DatabaseSetupアノテーションを使用することで テストコードにテストデータを定義したファイルを読み込ませることができる。 @DatabaseSetupアノテーションはクラスレベル、メソッドレベルで指定でき、メソッドレベルに指定した場合は指定した メソッド、クラスレベルで指定した場合は各メソッドのテスト実行前に指定したファイルでデータのセットアップが行われる。

本章では、Excel形式(.xlsx)のデータ定義ファイルを使用することを前提に説明する。 Excel形式に対応するDataSetLoaderインタフェースの実装例を以下に示す。

  • XlsDataSetLoader.java

public class XlsDataSetLoader extends AbstractDataSetLoader { // (1)

    @Override
    protected IDataSet createDataSet(
            Resource resource) throws IOException, DataSetException {
        try (InputStream inputStream = resource.getInputStream()) {
            return new XlsDataSet(inputStream);
        }
    }
}

項番

説明

(1)
Spring Test DBUnitが提供する抽象基底クラスであるcom.github.springtestdbunit.dataset.AbstractDataSetLoaderを利用して、Excel形式のデータ定義ファイルのXlsDataSetLoaderクラスを定義する。
  • MemberRepositoryDbunitTest.java

// omitted
@DbUnitConfiguration(dataSetLoader = XlsDataSetLoader.class) // (1)
@DatabaseSetup("classpath:META-INF/dbunit/setup_MemberLogin.xlsx")
public class MemberRepositoryDbunitTest {
    // omitted
}

項番

説明

(1)
@DbUnitConfigurationアノテーションにXlsDataSetLoaderクラスを指定することで、 @DatabaseSetupアノテーションを使用したExcel形式のデータ定義ファイル読込みができるようになる。
  • Excel形式のデータ定義ファイル(setup_MemberLogin.xlsx)

../../_images/PreparationForTestExcelFile.png

Excel形式のデータ定義ファイルでは、各シートが各テーブルに対応する。 シート名にはテーブル名、シートの一行目にはカラム名を設定する。 二行目以降にテーブルに挿入されるデータを記述する。


Note

CSV形式のデータ定義ファイルを使用する場合

DBUnitでCSV形式のデータ定義ファイルを使用する場合は、IDataSetインタフェースの実装クラスとして org.dbunit.dataset.csv.CsvDataSet.CsvDataSetクラスを使用することで実現できる。

Note

DBUnitがデフォルトで読み込むファイル形式について

DBUnitは、デフォルトでFlat XML形式のデータ定義ファイルをサポートしている。

Spring Test DBUnitを使用した場合は、@DbUnitConfigurationdataSetLoaderを指定しなかった場合、 Flat XML形式のファイルに対応したIDataSetインタフェースの実装クラスである org.dbunit.dataset.xml.FlatXmlDataSetクラスが使用される。

Flat XML形式のデータ定義ファイル例を以下に示す。

  • setup_MemberLogin.xml

<!-- (1) -->
<?xml version='1.0' encoding='UTF-8'?>
<dataset>
  <MEMBER_LOGIN CUSTOMER_NO="0000000001"
    PASSWORD="{pbkdf2}1030550073b359714fe2f7537fa1a794a5b0866c7adf62f7f974ff0492681d0db41f95c66be98f94"
    LAST_PASSWORD="{pbkdf2}8f702ea4c50c58921c8be11b811a535d5c29856fc4f50b8545efe13914ac87e880cb5b7d390e770b"
    LOGIN_DATE_TIME="2017-09-13 16:47:04.283" LOGIN_FLG="FALSE" />
</dataset>

項番

説明

(1)
dataset要素配下の各XML要素は、テーブルのレコードに対応しており、各XMLの要素名にテーブル名、 属性名にカラム名、属性値に投入するデータを定義する。例では、MEMBER_LOGINテーブルに値を定義している。

10.2.1.3. テスト実装例で使用する設定ファイル

Spring Testの DI機能を使用することでテストで使用するBeanを定義した設定ファイルを読み込み、テスト時に使用することができる。 詳細はSpring TestのDI機能を参照されたい。

本章では、テストを行う際に必要な設定をtest-context.xmlに定義し、その設定ファイルをテスト時の共通設定としている。 なお、test-context.xmlはdomainプロジェクトのsrc/test/resources/test-context.xmlから <import resource="classpath:META-INF/spring/projectName-domain.xml" />を削除し、各層ごとにアプリケーションが 保持する設定ファイル(sample-infra.xmlなど)と組み合わせて読み込む方針でテストを実装している。

Note

単体テストで利用する設定ファイルの作成単位

本章では上記のように設定ファイルを作成しているが、実際に設定ファイルを用意する際には、アーキテクトが業務要件を考慮して 共通設定を定義し、それを元にテスト実装チームで必要な設定を追加するようにして対応すること。

以下に本章の実装例で使用する設定ファイルを示す。

  • test-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:context="http://www.springframework.org/schema/context"
  xmlns:aop="http://www.springframework.org/schema/aop"
  xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

  <context:property-placeholder
    location="classpath*:/META-INF/spring/*.properties" />

  <!-- Add Bean definition according to business. -->
  <!-- (1) -->
  <bean id="exceptionLogger" class="org.terasoluna.gfw.common.exception.ExceptionLogger" />

  <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource" />
  </bean>

  <!-- (2) -->
  <bean id="passwordEncoder" class="org.springframework.security.crypto.password.DelegatingPasswordEncoder">
    <constructor-arg name="idForEncode" value="pbkdf2" />
    <constructor-arg name="idToPasswordEncoder">
      <map>
        <entry key="pbkdf2">
          <bean class="org.springframework.security.crypto.password.Pbkdf2PasswordEncoder" />
        </entry>
        <entry key="bcrypt">
          <bean class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
        </entry>
        <!-- When using commented out PasswordEncoders, you need to add bcprov-jdk15on.jar to the dependency.
        <entry key="argon2">
          <bean class="org.springframework.security.crypto.argon2.Argon2PasswordEncoder" />
        </entry>
        <entry key="scrypt">
          <bean class="org.springframework.security.crypto.scrypt.SCryptPasswordEncoder" />
        </entry>
        -->
      </map>
    </constructor-arg>
  </bean>
  <!-- Add Bean definition according to business. -->

  <aop:aspectj-autoproxy />

</beans>

項番

説明

(1)
テスト実施に必要なBeanを定義する。
(2)
ここでは、テスト例を実装するためにpasswordEncoderのBean定義を追加している。
Bean定義については、業務に応じて適宜追加されたい。