DBUnit¶
DBUnitとは¶
JUnit試験にてDBへの事前データの登録や、登録・更新・削除後のテーブルの状態を期待値との比較を容易にするためのライブラリ
セットアップ¶
mavenを利用してセットアップを実施
https://mvnrepository.com/artifact/org.dbunit/dbunit
<!-- https://mvnrepository.com/artifact/org.dbunit/dbunit --> <dependency> <groupId>org.dbunit</groupId> <artifactId>dbunit</artifactId> <version>2.7.0</version> <scope>test</scope> </dependency>
利用方法¶
主な利用シーンとして以下の2つのシーンで利用します。
データの事前登録処理
検索、更新、削除のSQLを実行する際に対象のデータを登録するための処理
Connection con = DriverManager.getConnection(url, user, passwd); IDatabaseConnection dbconn = new DatabaseConnection(con); // データの事前登録処理 File dataExcel = new File(getClass().getResource("/sample_table_data.xlsx").getPath()); IDataSet dataset = new XlsDataSet(dataExcel); // ExcelのデータをDBへ適用する DatabaseOperation.CLEAN_INSERT.execute(dbconn, dataset);
DBデータとの比較処理
登録、更新、削除後のデータベースの状態と期待値のExcelの比較するための処理
// 期待値を取得 File dataExcel = new File(getClass().getResource("/sample_table_data_insert_result.xlsx").getPath()); IDataSet expectedDataSet = new XlsDataSet(dataExcel); ITable expectedTable = expectedDataSet.getTable(tableName); // 実際値を取得 IDatabaseConnection dbconn = new DatabaseConnection(con); ITable actualTable = dbconn.createDataSet().getTable(tableName);
サンプル¶
今回はpostgresql用のテーブルに対してSQLを発行するためのDaoに対してテストケースを作成することで利用方法を確認します。
サンプル用のソース : https://github.com/snowhiro/dbunit-exsample
確認用テーブルの作成
create table sample_table ( id bigint, doc_text text, now_time timestamp ) ALTER TABLE sample_table ADD PRIMARY KEY(id);
検索メソッドの場合
対象のメソッド
public Optional<SampleTable> findSampleTable(Long id) { String selectSql = "SELECT * FROM sample_table where id = ?"; try (PreparedStatement stmt = con.prepareStatement(selectSql)) { stmt.setLong(1, id); ResultSet rs = stmt.executeQuery(); SampleTable st = null; while(rs.next()) { st = new SampleTable(); st.setId(rs.getLong("id")); st.setDocText(rs.getString("doc_text")); st.setNowTime(rs.getTimestamp("now_time")); } return Optional.ofNullable(st); } catch (Exception e) { throw new RuntimeException("Daoの実行でエラーが発生しました。", e); } }テストケース
@Test public void findSampleTable() throws Exception { IDatabaseConnection dbconn = new DatabaseConnection(con); // データの事前登録処理 File dataExcel = new File(getClass().getResource("/sample_table_data.xlsx").getPath()); IDataSet dataset = new XlsDataSet(dataExcel); // ExcelのデータをDBへ適用する DatabaseOperation.CLEAN_INSERT.execute(dbconn, dataset); // 処理を実行する Long id = 10L; SampleTable st = dao.findSampleTable(id).get(); // 検証処理 assertEquals("10番目のデータ", st.getDocText()); LocalDateTime d1 = LocalDateTime.of(2020, 05, 05, 10, 30, 01); Timestamp exNowTime = new Timestamp(Date.from(d1.atZone(ZoneId.systemDefault()).toInstant()).getTime()); assertEquals(exNowTime, st.getNowTime()); }初期登録用のExcel
![]()
登録メソッドの場合
public int insertSampleTable(SampleTable st) { String insertSql = "insert into sample_table (id, doc_text, now_time) values (?, ?, ?)"; try (PreparedStatement stmt = con.prepareStatement(insertSql)) { stmt.setLong(1, st.getId()); stmt.setString(2, st.getDocText()); stmt.setTimestamp(3, st.getNowTime()); return stmt.executeUpdate(); } catch (Exception e) { throw new RuntimeException("Daoの実行でエラーが発生しました。", e); } }@Test public void insertSampleTable() throws Exception { SampleTable st = new SampleTable(); st.setId(100L); st.setDocText("テスト用のインサートデータ"); st.setNowTime(new Timestamp(Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant()).getTime())); int insertCount = dao.insertSampleTable(st); assertEquals(1, insertCount); String tableName = "sample_table"; // 期待値を取得 File dataExcel = new File(getClass().getResource("/sample_table_data_insert_result.xlsx").getPath()); IDataSet expectedDataSet = new XlsDataSet(dataExcel); ITable expectedTable = expectedDataSet.getTable(tableName); // 実際値を取得 IDatabaseConnection dbconn = new DatabaseConnection(con); ITable actualTable = dbconn.createDataSet().getTable(tableName); // 全てのカラムを比較する場合(今回の場合システム日時の登録のため必ずエラーとなる) //Assertion.assertEquals(expectedTable, actualTable); // システム日時の登録カラムなど除外用のカラムを追加する場合 フィルターを設定する String[] filterColumns = {"now_time"}; ITable expectedFilterTable = DefaultColumnFilter.excludedColumnsTable(expectedTable, filterColumns); ITable actualFilterTable = DefaultColumnFilter.excludedColumnsTable(actualTable, filterColumns); // 比較 Assertion.assertEquals(expectedFilterTable, actualFilterTable); }期待値の用のExcelファイル
![]()
更新メソッドの場合
public int updateSampleTable(SampleTable st) { String insertSql = "update sample_table set doc_text = ? , now_time = ? where id = ?"; try (PreparedStatement stmt = con.prepareStatement(insertSql)) { stmt.setString(1, st.getDocText()); stmt.setTimestamp(2, st.getNowTime()); stmt.setLong(3, st.getId()); return stmt.executeUpdate(); } catch (Exception e) { throw new RuntimeException("Daoの実行でエラーが発生しました。", e); } }@Test public void updateSampleTable() throws Exception { IDatabaseConnection dbconn = new DatabaseConnection(con); // データの事前登録処理 File dataExcel = new File(getClass().getResource("/sample_table_data.xlsx").getPath()); IDataSet dataset = new XlsDataSet(dataExcel); // ExcelのデータをDBへ適用する DatabaseOperation.CLEAN_INSERT.execute(dbconn, dataset); SampleTable st = new SampleTable(); st.setId(10L); st.setDocText("テスト用の更新データ"); LocalDateTime d1 = LocalDateTime.of(2020, 05, 05, 12, 20, 52); st.setNowTime(new Timestamp(Date.from(d1.atZone(ZoneId.systemDefault()).toInstant()).getTime())); int updateCount = dao.updateSampleTable(st); assertEquals(1, updateCount); String tableName = "sample_table"; // 期待値を取得 File exExcel = new File(getClass().getResource("/sample_table_data_update_result.xlsx").getPath()); IDataSet expectedDataSet = new XlsDataSet(exExcel); ITable expectedTable = expectedDataSet.getTable(tableName); // 実際値を取得 ITable actualTable = dbconn.createDataSet().getTable(tableName); // 全てのカラムを比較 Assertion.assertEquals(expectedTable, actualTable); }初期登録用のExcel
![]()
期待値の用のExcelファイル
![]()
メリット¶
- ・試験時データの外出しが容易に行える
- (フォーマットとしては「CSV」「XML」「excel」の3種類)
- ・insert文で記載する方式に比べてメンテナンス性が良い。
- ・DBの比較処理を容易に実施することができる。登録、更新、削除等のDBの状態を指定ファイルに記載することで比較可能
デメリット¶
- ・データのパースを実施する分試験実施時の速度は低下する。
- ・フォーマットにexcelを利用する場合、excel環境が必要になる。
- ・excelのシート名の制約があるため長いテーブル名の場合xmlの利用が必要となる。(最大31文字まで)
参考サイト¶
【超初心者向け】DBUnit超入門