DbUnitの使い方

# はじめに

## 前提条件
- DB接続が出来ている。（出来ていない場合は、DBViewer等で確認してください。）
- 依存関係の設定済み

## バージョン
- junit5
- dbunit 2.7.3

# DbUnit全体的な流れ
## 前処理
- データのバックアップ
- テストデータの投入
## 後処理
- バックアップファイルを適用

# ディレクトリ構成

```
プロジェクト名
├ src
   └ main
   └ test
      └ java/com/example
          └ dbunit
             ├── m_user.csv
             └── m_task.csv
          └ DbUnitSetting.java
          └ table-ordering.txt
```

`data.csv`は、テストデータを入れるためのcsvファイルです。
`table-ordering.txt`については後ほど解説します。

# 実装
今回はテストデータはcsvファイルを使って投入します。

```DbUnitSetting.java
public class DbUnitSetting {

    private final JdbcTemplate jdbcTemplate;
    private File backupFile;
    private FileOutputStream out;
    private FileInputStream in;

    public DbUnitSetting(JdbcTemplate jdbcTemplate) {
	    this.jdbcTemplate = jdbcTemplate;
    }

    /**
     * DBのバックアップ<br/>
     * 最初のテストを行う時に、1回だけ行う
     * 
     * @throws SQLException
     * @throws DatabaseUnitException
     */
    @BeforeAll
    public void setUp() throws SQLException, DatabaseUnitException {
    	String jdbcUrl = "jdbc:mysql://localhost/スキーマ";
    	Connection jdbConnection = DriverManager.getConnection(jdbcUrl, "ユーザ名", "パスワード");
    	IDatabaseConnection connection = new DatabaseConnection(jdbConnection);
    	try {
    	    QueryDataSet parDataSet = new QueryDataSet(connection);
    	    // テーブルを指定
    	    parDataSet.addTable("テーブル名");
    	    String backupDir = "src/test/java/com/example/";
    	    this.backupFile = File.createTempFile("backup", ".xml", new File(backupDir));
    	    this.out = new FileOutputStream(this.backupFile);
    	    FlatXmlDataSet.write(parDataSet, this.out);
    	    this.out.flush();
    	} catch (Exception e) {
    	    e.printStackTrace();
    	} finally {
    	    connection.close();
    	}
    }

    /**
     * バックアップしたファイルの復元<br/>
     * 全てのテスト後が終了したら、1回だけ行う
     * 
     * @throws Exception
     */
    @AfterAll
    public void tearDown() throws Exception {
    	String jdbcUrl = "jdbc:mysql://localhost/スキーマ";
    	Connection jdbConnection = DriverManager.getConnection(jdbcUrl, "ユーザ名", "パスワード");
    	IDatabaseConnection connection = new DatabaseConnection(jdbConnection);
    	try {
    	    in = new FileInputStream(backupFile);
    	    IDataSet dataSet = new FlatXmlDataSetBuilder().build(in);
    	    DatabaseOperation.CLEAN_INSERT.execute(connection, dataSet);
    	} catch (Exception e) {
    	    e.printStackTrace();
    	} finally {
    	    connection.close();
    	}
    }

    /**
     * テストデータの投入<br/>
     * テストを開始する前に毎回行う
     * 
     * @throws Exception
     */
    @BeforeEach
    public void insertTestData() throws Exception {
        String jdbcUrl = "jdbc:mysql://localhost/スキーマ";
    	Connection jdbConnection = DriverManager.getConnection(jdbcUrl, "ユーザ名", "パスワード");
    	IDatabaseConnection connection = new DatabaseConnection(jdbConnection);
    	try {
    	    IDataSet dataSet = new CsvDataSet(new File("src/test/java/com/example/test/dbunit"));
    	    new InsertIdentityOperation(DatabaseOperation.CLEAN_INSERT).execute(dbConnection, dataSet);
    	} catch (Exception e) {
    	    e.printStackTrace();
    	} finally {
    	    connection.close();
    	}
    }
}
```

# 解説
## DB接続
```Test.java
Connection connection = jdbcTemplate.getDataSource().getConnection();
IDatabaseConnection connection = new DatabaseConnection(connection);
```

DB接続の設定を`application.propertise(yml)`に記載してある場合は、上記のように実装します。

`application.properties(ymml)`を使う場合は、`src/test/resources`直下にテスト用の設定で配置します。 `src/test/resources`に`application.properties(yml)`が無い場合は`src/main/resources`に配置されている`application.properties(yaml)`の情報が適用されます。
`src/test/java`
設定したDBを使う為、`@AutoConfigureTestDatabase(replace = 
AutoConfigureTestDatabase.Replace.NONE)`をつけます。


## バックアップするテーブルの指定
```Test.java
parDataSet.addTable("TABLE_NAME");
```
バックアップしたいテーブルを指定する。
複数のテーブルをバックアップすることも可能。

## データ投入の仕方
```Test.java
DatabaseOperation.CLEAN_INSERT.execute(connection, dataSet);
```
指摘された全てのテーブルのデータが消され、インサートされます。
実行した結果一意性制約違反となる場合は例外が発生する。

## csvファイルの準備
- テーブル名.csvというファイル名を用意する
- csvファイルの1行目に列名、2行目以降にデータを記載する
- 「table-ordering.txt」というファイルを作成する
- table-ordering.txtに登録するテーブルを記載する。
    - テーブルを書いた順番でデータを投入される。
    - table-ordering.txtに記載したテーブルが全て投入される為、記載したテーブルのバックアップを全てとった方がよい。

csvファイルの書き方は以下の通り。
記載しなかった列にはnullが入りる。
```m_user.csv
name,age,email
bob,26,bob@example.com
alice,24,alice@example.com
```

```table-ordering.txt
m_user
m_task
```

# 終わりに
もし間違いがありましたら、編集リクエスト又はコメントお願いします。


# 参考文献
- [DBUnit - DatabaseOperationの挙動](https://qiita.com/Chayata/items/1ce99d2d908cacc57298)
- [意外に知らないDbUnitでCSVを使う方法](https://www.sakatakoichi.com/entry/20080828/1219885803)