H2 + DbSetupでのcsvによるテストデータのロード

# 背景
[DbSetup](http://dbsetup.ninja-squad.com/)はJavaのユニットテストでDBに初期データをロードするのに非常に便利なライブラリです。ただし、大量データや多数の列からなるデータのロードには適しておらず、その場合には[DbUnit](http://dbunit.sourceforge.net/)等が便利と思われます。これはDbSetupの前提条件である「ユニットテストで必要となるテストデータは大して多くない」というものの現れであり、実際その通りなので、欠点ではありません。

しかしながら、ある種の集計機能だとか、ユニットテストの可読性がテストデータをCSVなど外部ファイルに残した方が見やすい、というケースが稀に発生します。その場合のためだけにDbUnitとか使うのもだるいので、DbSetupだけで済ませる方法は何かないか、と考えました。

# 解決案
今回取った方法としては、まずテストデータは素直にcsvファイルにします。それから、そのテストデータを[H2 Database Engine](http://www.h2database.com/html/main.html)の[CSVREAD](http://www.h2database.com/html/functions.html#csvread)関数で読み込み、データロードを行う```INSERT INTO ... SELECT * FROM CSVREAD(...)```
のSQLを、DbSetupで生のSQLを実行できる[Operations#sql](http://dbsetup.ninja-squad.com/apidoc/2.1.0/com/ninja_squad/dbsetup/Operations.html#sql-java.lang.String...-)に渡します。

# ソースコード
クラスパスの通っている場所に適当なファイルを作ります。

```:src\test\resources\hoge.csv
1,かがみ
2,ほげ
3,foo
4,bar
5,piyo
```

pom.xmlに依存性を追加します。

```xml:pom.xml
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.192</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.ninja-squad</groupId>
            <artifactId>DbSetup</artifactId>
            <version>2.1.0</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
```

ソースコード。

```java
package kagamihoge.dbsetupwithh2csvread;

import static com.ninja_squad.dbsetup.Operations.sequenceOf;
import static com.ninja_squad.dbsetup.Operations.sql;

import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import org.junit.Before;
import org.junit.Test;

import com.ninja_squad.dbsetup.DbSetup;
import com.ninja_squad.dbsetup.destination.DriverManagerDestination;
import com.ninja_squad.dbsetup.operation.Operation;

public class HogeTest {

    @Before
    public void setUp() throws Exception {
        URL csvResource = getClass().getClassLoader().getResource("hoge.csv");
        Path csv = Paths.get(csvResource.toURI()).toAbsolutePath();

        Operation operation = sequenceOf(
                sql("CREATE TABLE hoge(hogeid VARCHAR(16) PRIMARY KEY NOT NULL, hogename VARCHAR(100))"),
                sql("INSERT INTO hoge(hogeid, hogename) SELECT * FROM CSVREAD('" + csv + "','hogeid, hogename','UTF-8')"));

        DbSetup dbSetup = new DbSetup(
                new DriverManagerDestination("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1", "sa", ""), operation);
        dbSetup.launch();
    }

    @Test
    public void test1() throws SQLException {
        // 注意：エラー処理・DBのクローズ処理が適当なので、適宜読み替えて下さい。
        Connection con = DriverManager.getConnection("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1", "sa", "");
        Statement st1 = con.createStatement();

        ResultSet rs = st1.executeQuery("SELECT hogeid, hogename FROM hoge");
        while (rs.next()) {
            System.out.println(rs.getString(1) + "," + rs.getString(2));
        }

        st1.close();
        con.close();
    }
}

```

setUpの最初では、CSVREAD関数に渡すファイルの絶対パスを取得するため、クラスパス上に配置したテストデータのCSVファイル(hoge.csv)から絶対パスを取得しています。

そのあと、DbSetupのOperations#sqlで```INSERT INTO ... SELECT * FROM CSVREAD(...)```を実行することで、テストデータのロードを行います。

# 参考文献
- [Ｈ２ ＤＢ　インストール・設定メモ](http://homepage2.nifty.com/yoks/TechNote/H2/H2_MnFrm.htm)
- [H2をインメモリで動かすときの注意 - Yamkazu's Blog](http://yamkazu.hatenablog.com/entry/20100901/1283335238)
- [ClassLoaderでリソース(URL)を取得 - Java Swing Tips](http://ateraimemo.com/Swing/ClassLoader.html)
- [H2 Databaseで、CSV／TSVファイルにSQLを実行する - CLOVER](http://d.hatena.ne.jp/Kazuhira/20151219/1450508822)