Webエンジニアのメモ帳

技術的な話を中心に書いています。

【Java】DBUnitテスト入門

JavaDBUnitというライブラリを使い、実際にDBと通信を行うテストを行う方法を説明します。

テーブルの構成

テストで使うDBは以下の通りとします。

  • DB名...test
  • テーブル名...animal
mysql> desc animal;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id    | int(11)      | YES  |     | NULL    |       |
| name  | varchar(100) | YES  |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

テーブルにデータは入っていません。

テストコード

このテーブルにレコードを追加し、レコードが追加されたかどうか確認する、という内容です。

テストコード中で使うinsert.xlsxとexpected.xlsxは以下のような内容です。 f:id:iberia9lavapies:20190720105314p:plain

insert.xlsxの内容をanimalテーブルに挿入し、その結果がexpected.xlsxと同じようになっているかを確認します。

また、xlsxファイルにおけるシート名はDBにおけるテーブル名と同じにする必要があります。

import org.dbunit.database.DatabaseConfig;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.ITable;
import org.dbunit.dataset.excel.XlsDataSet;
import org.dbunit.ext.mysql.MySqlMetadataHandler;
import org.dbunit.operation.DatabaseOperation;
import org.junit.Test;
import static org.dbunit.Assertion.assertEquals;
import java.io.File;
import java.sql.Connection;
import java.sql.DriverManager;
public class InsertTest {
  String url = "jdbc:mysql://localhost:3306";
  String user = "testUser";
  String password = "testPass";
  @Test
  public void insertTest() throws Exception {
    Connection conn = DriverManager.getConnection(url, user, password);
    IDatabaseConnection dbconn = new DatabaseConnection(conn, "test");
    DatabaseConfig config = dbconn.getConfig();
    config.setProperty(DatabaseConfig.PROPERTY_METADATA_HANDLER, new MySqlMetadataHandler());
    
    IDataSet dataset = new XlsDataSet(new File("data/insert.xlsx"));
    DatabaseOperation.CLEAN_INSERT.execute(dbconn, dataset);
    IDataSet expectedDataSet = new XlsDataSet(new File("data/expected.xlsx"));
    ITable expectedTable = expectedDataSet.getTable("animal");
    
    IDataSet actualDataSet = dbconn.createDataSet();
    ITable actualTable = actualDataSet.getTable("animal");
    assertEquals(expectedTable, actualTable);
  }
}

エラーが発生しがちなポイント

このテストコードの実装に際して、何箇所かエラーが発生して解決に時間を使ってしまったので、メモしておきます。

ファイルがないというエラーが出る

このエラーが出る場合は

new File(ファイル名)

としているところで、ファイル名に絶対パスを指定してください。

NoSuchColumnExceptionというエラーが出る

org.dbunit.dataset.NoSuchColumnException: animal.ID -  (Non-uppercase input column: ID) in ColumnNameToIndexes cache map. Note that the map's column names are NOT case sensitive.

というエラーが発生し、解決に時間を取られました。

こちらは、以下の2行を追加することにより解決しました。

DatabaseConfig config = dbconn.getConfig();
config.setProperty(DatabaseConfig.PROPERTY_METADATA_HANDLER, new MySqlMetadataHandler());

assertEquals()でエラー

assertEquals()というメソッドはDBUnitではなくJUnitの方にも存在しています。

またその双方でオーバーロードされており、assertEquals()というメソッドが大量に存在します。

assertEquals()のところでエラーになる場合、間違ったassertEquals()メソッドを使っていないか確かめてみてください。

補足

通常DBUnitテストを行う場合、@Beforeアノテーションを付与したメソッドで現在DBにあるデータを退避させ、テスト終了後は@Afterアノテーションを付与したメソッドで退避させたデータをもとに戻す、という処理を行います。

今回はDBUnitの基本的な使い方を説明したかったので省きましたが、この方法は調べればすぐに出てくると思います。

また、

DatabaseOperation.CLEAN_INSERT.execute(dbconn, dataset);

としている箇所ではCLEAN_INSERTの代わりにINSERTを使えます。INSERTを使った場合は、animalテーブル上のデータは消去されませんが、CLEAN_INSERTを使うと、animalテーブルのデータが全て消去されてからデータが挿入されます。