PR

JUnitとDBUnitでDB接続処理のテストを自動化する

プログラミング
記事内に広告が含まれています。

この記事では、DB接続処理のプログラムをDBUnitでテスト自動化する方法を紹介します

こんな悩みを持っている方におすすめ!
  • DBUnitの利用方法が知りたい
  • DBと連結したテストコードを知りたい
  • DBUnitを利用する際の注意点を知りたい

昨今では単体テストを自動化することが主流となっています。

ただ、「単体テストの自動化」と言っても、DBとの接続までテストするプロジェクトもあれば、DBとの接続をモック化して進めるプロジェクトもあり、検証方法は様々です。

単体テストでSQLの妥当性まで確認できたほうが早くバグを発見できるため、簡単に実現できるならDB接続も含めてテストしたいですよね。

しかし、DBの接続までテストする場合、テスト用のDBの準備やテストで作成されたデータの廃棄方法など調べることが多く難しく感じてしまいます。

そこでこの記事では、単体テストの自動化でDB接続を行うときのテスト検証方法をまとめました。

DBUnitの導入から、テストコードの書き方、DBUnitの注意点にいたるまで解説しています。

テストを自動化する際に役立つ内容となってますので、ぜひ最後までご覧ください。

利用技術の紹介

当記事で利用する技術を簡単に紹介します。(すでにご存知のかたは読みとばしてください。)

JUnit

Javaプログラムの単体テストを行うためのフレームワーク。テストコードの記述と結果の確認が簡単になる。

JUnitの公式サイト

DBUnit

DBを操作する単体テストを簡単にするためのフレームワーク。JUnitを拡張したもので、データベースにアクセスするプログラムの単体テストが簡単に実現できる。

DBUnitの公式サイト

DB接続処理のテスト実現方法

ここから、DB接続のテストを自動化する方法を解説します。

今回は、「データ登録処理を行うメソッド実行後、DBに登録された結果が正しいか」を検証するテストケースを例として解説します。

DBUnitの導入

DBUnitは、Mavenでインストールします。

pom.xmlに以下を記述します。

<dependency>
    <groupId>org.dbunit</groupId>
    <artifactId>dbunit</artifactId>
    <version>2.7.0</version>
    <scope>test</scope>
</dependency>

Mavenのインストールコマンドを実行し、DBUnitをインストールします。

mvn install

POIの導入

DBUnitを使ったテストでは、テスト時に必要なテストデータを準備できます。投入するデータは、xmlまたはExcelで定義が可能です。

本記事では、直感的にわかりやすいExcelで定義し進めます。DBUnitでは、ExcelのデータをロードするためにPOI(*)を利用しているため、インストールしておきます。

pom.xmlのPOIの情報を記述します。

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>3.9</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.9</version>
    <scope>test</scope>
</dependency>
POIとは

JavaでExcelファイルを読み書きするフリーのライブラリ。Excelがインストールされていない環境でもExcelファイルを読み書きすることが特徴。

POIのバージョンは、DBUnitが内部的に利用しているバージョンと同じバージョンを利用する必要があります。

異なったバージョンのPOIをインストールした場合、正しいコードにも関わらずExcelデータの操作時にエラーとなるのでご注意ください。

テストデータの準備

テストに必要なデータを準備します。

Excelでテストデータを定義するときはシート名を「テーブル名」にします。複数テーブルを読み込ませたい場合は、シートをテーブル数分用意します。

各シートの内容は一行目がテーブル項目、二行目以降はデータとして扱われます。

DBのデータ型に合わせて、セルの書式を設定します。

テーブルのデータ型Excelのセル書式
VARCHAR2、CHAR文字列
NUMBER数値

DB接続処理のテストコード

DB接続を含めたテストコード全体はこちらです。正しくデータが取得できることを想定したテストケースです。

import org.dbunit.DBTestCase;
import org.dbunit.PropertiesBasedJdbcDatabaseTester;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.xml.FlatXmlDataSetBuilder;
import org.dbunit.operation.DatabaseOperation;
import org.dbunit.dataset.excel.XlsDataSet;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

public class SelectTest extends DBTestCase {

    public SelectTest() {
        System.setProperty(PropertiesBasedJdbcDatabaseTester.DBUNIT_DRIVER_CLASS, "oracle.jdbc.driver.OracleDriver");
        System.setProperty(PropertiesBasedJdbcDatabaseTester.DBUNIT_CONNECTION_URL, "jdbc:oracle:thin:@localhost:1521:yourdb");
        System.setProperty(PropertiesBasedJdbcDatabaseTester.DBUNIT_USERNAME, "username");
        System.setProperty(PropertiesBasedJdbcDatabaseTester.DBUNIT_PASSWORD, "password");
    }

    @Override
    protected IDataSet getDataSet() throws Exception {
        // Excelファイルからテストデータセットをロード
        return new XlsDataSet(new FileInputStream("path/to/your/dataset.xls"));
    }

    @Override
    protected DatabaseOperation getSetUpOperation() throws Exception {
        // テスト前にデータセットをデータベースにインサート
        return DatabaseOperation.CLEAN_INSERT;
    }

    @Override
    protected DatabaseOperation getTearDownOperation() throws Exception {
        // テスト後にデータベースをクリーンアップ
        return DatabaseOperation.DELETE_ALL;
        // return DatabaseOperation.NONE;
    }

    public void testSelect() throws Exception {
        // データベース接続を取得
        Connection connection = getConnection().getConnection();

        try {

            // ※ここでデータ登録処理のメソッドを実行したとする
            // example.testInsert(); ←実行メソッド例

            // ---------
            // 結果を検証
            // ---------
            // SELECT文を実行
            Statement statement = connection.createStatement();
            ResultSet resultSet = statement.executeQuery("SELECT * FROM your_table WHERE id = 1");
            // 取得された各項目の値が期待値通りか検証
            assertTrue("Result set is empty", resultSet.next());
            assertEquals("Test Name 1", resultSet.getString("name"));
            assertEquals(123, resultSet.getInt("value"));

            // 結果セットに次の行がないことを確認
            assertFalse("Result set contains more than one row", resultSet.next());
        } finally {
            // リソースをクリーンアップ
            connection.close();
        }
    }
}

順番にポイントを解説していきます。

ポイント1:DBTestCaseを継承

DBUnitを利用する場合テストクラスは、「DBTestCase」 を継承します。

public class SelectTest extends DBTestCase {

ポイント2:テストデータのロード

テストデータのロードは、DBTestCaseからオーバーライドされたメソッドで行います。

    @Override
    protected IDataSet getDataSet() throws Exception {
        // Excelファイルからテストデータセットをロード
        return new XlsDataSet(new FileInputStream("path/to/your/dataset.xls"));
    }

    @Override
    protected DatabaseOperation getSetUpOperation() throws Exception {
        // テスト前にデータセットをデータベースにインサート
        return DatabaseOperation.CLEAN_INSERT;
    }

「getDataSet」メソッドの中でデータをロード、「getSetUpOperation」メソッドでデータセットの取り扱い方法を設定します。

今回はテスト前にデータを登録するモードとしました。

ポイント3:DBとの接続テスト

接続情報の設定
    public SelectTest() {
        System.setProperty(PropertiesBasedJdbcDatabaseTester.DBUNIT_DRIVER_CLASS, "oracle.jdbc.driver.OracleDriver");
        System.setProperty(PropertiesBasedJdbcDatabaseTester.DBUNIT_CONNECTION_URL, "jdbc:oracle:thin:@localhost:1521:yourdb");
        System.setProperty(PropertiesBasedJdbcDatabaseTester.DBUNIT_USERNAME, "username");
        System.setProperty(PropertiesBasedJdbcDatabaseTester.DBUNIT_PASSWORD, "password");
    }

DBと接続するので、接続情報を設定します。

DRIVER_CLASSはoracleに設定していますが、利用するDBに合わせて変更してください。

DBUnitで利用するスキーマのテーブルは、基本的に空の状態が望ましく、テスト完了後に各テーブルのデータをクリアします。

そのため、DBUnitで接続するスキーマは開発者が利用するスキーマと別環境を準備することを推奨します

DBに登録された結果のテスト
    public void testSelect() throws Exception {
        // データベース接続を取得
        Connection connection = getConnection().getConnection();

        try {

            // ※ここでデータ登録処理のメソッドを実行したとする
            // example.testInsert(); ←実行メソッド例

            // ---------
            // 結果を検証
            // ---------
            // SELECT文を実行
            Statement statement = connection.createStatement();
            ResultSet resultSet = statement.executeQuery("SELECT * FROM your_table WHERE id = 1");
            // 取得された各項目の値が期待値通りか検証
            assertTrue("Result set is empty", resultSet.next());
            assertEquals("Test Name 1", resultSet.getString("name"));
            assertEquals(123, resultSet.getInt("value"));

            // 結果セットに次の行がないことを確認
            assertFalse("Result set contains more than one row", resultSet.next());
        } finally {
            // リソースをクリーンアップ
            connection.close();
        }
    }

SQLで取得された結果の値を比較しています。取得件数が1件であることを確認するため、「resultSet.next()」がFalseを返すことも検証しています。

結果検証前イン、データ登録などテスト対象のプログラムを実行するコードを記述してください。

ポイント4:テストデータのクリア

    @Override
    protected DatabaseOperation getTearDownOperation() throws Exception {
        // テスト後にデータベースをクリーンアップ
        return DatabaseOperation.DELETE_ALL;
        // return DatabaseOperation.NONE;
    }

DBUnitでは、「getTearDownOperation」メソッドで、テスト完了後にテストデータをどのように取り扱うかを設定します。

通常、テストで利用したデータは元にもどすため、「DatabaseOperation.DELETE_ALL」を設定しデータをクリアしています。ここでクリアされるデータは「getDataSet」でロードしたテーブルに対して実行されます。

今回の場合だと、「your_table」、「mine_table」のデータが全て空になります

テスト後にデータベースに対して何もしたくない場合は、「DatabaseOperation.NONE」を設定します。

まとめ

  • 「テストデータのロード」、「テスト」、「テストデータのクリア」の3ステップでテスト
  • DBとの接続テストは、開発者と独立したテスト用のスキーマが必要

DBとの接続部分のテストは、DBUnitを利用することで簡単にテストを自動化できます。

テスト用のスキーマの準備が必要ですが、開発者と独立したスキーマを用意することで想定外のデータによるテスト失敗が防止でき、テストの信頼性が向上します。

ロードするテストデータをExcelで定義できるため、データのメンテナンスもしやすく利便性が高いです。

ただし、DBUnitが内部的に利用しているPOIのバージョンが一致しない場合は予期せぬエラーに遭遇するため注意が必要です。

本記事が皆様の参考になれば幸いです。

関連記事:LambdaをJavaで作成するには?環境構築方法からデプロイ方法まで徹底解説!

コメント

タイトルとURLをコピーしました