easyb で dbunit - easyb dbunit プラグイン使用

easyb の dbunit(DBのユニットテストツール)用のプラグインを使ってみる事にする。
ちなみに、dbunit プラグインを使うと database_model メソッド(クロージャで DB に格納する初期レコードを指定できる)が使えるようになる。

使用した環境は以下の通り。

  • Groovy 1.5.6
  • Gant 1.4.0
  • easyb 0.9
  • easyb dbunit plugin 0.9
  • HSQLDB 1.8.0.5 (Grails 1.0.3 に同梱のものを使用)

振る舞いの定義

では、easyb で振る舞いを定義する。今回は簡単な DB へのアクセス用 Java クラスを振る舞いの定義対象とした。

ここで、dbunit プラグインによって追加される database_model はクロージャが返す XML 文字列を使って DB の初期レコードを設定する機能を有している。
ただし、デフォルト文字コードでバイト配列化したデータを使って FlatXmlDataSet(dbunit のクラス)を作成し、DB にレコード登録するため、HSQLDB に日本語文字列を格納する点で不都合が生じる。
今回は、これを回避するための措置として、dbunit プラグインの FlatXmlDataSet を生成している処理を上書きし、UTF-8XML を取り込むようにした。

ちなみに、XML の生成には Groovy の MarkupBuilder を使用した。

dataDao.story ファイル
import java.sql.DriverManager
import groovy.sql.Sql
import groovy.xml.MarkupBuilder

import org.dbunit.dataset.xml.FlatXmlDataSet
import org.disco.easyb.plugin.delegates.DBUnitDelegate

import sample.DataDao

//HSQLDB に日本語(UTF-8 で)を格納させるための措置
DBUnitDelegate.metaClass.getDataSet = {Closure model ->
    data = model.call() as String
    new FlatXmlDataSet(new ByteArrayInputStream(data.getBytes("UTF-8")))
}

dburl = "jdbc:hsqldb:./db/test1"
driver = "org.hsqldb.jdbcDriver"
user = "sa"
password = ""

scenario "データを検索する", {

    given "DBスキーマ定義", {
        sql = Sql.newInstance(dburl, user, password, driver)
        ddl = """
              DROP TABLE data IF EXISTS;
              CREATE TABLE data(ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL PRIMARY KEY, NAME VARCHAR(50), POINT INTEGER NOT NULL);
              COMMIT;
              """
        sql.execute(ddl)
    }

    and "初期データ", {
        //dbunit プラグインで追加される機能を使用
        database_model(driver, dburl, user, password) {
            def writer = new StringWriter()
            def builder = new MarkupBuilder(writer)

            //XML の定義
            builder.dataset() {
                data(name: "テスター1", point: 10)
                data(name: "fits", point: 5)
            }

            //XML を生成
            writer.toString()
        }
    }

    when "DB検索クラスのインスタンス作成", {
        dbObj = new DataDao(DriverManager.getConnection(dburl, user, password))
    }

    then "test1 の検索結果数は 1 になるはず", {
        resultList = dbObj.searchWithName("テスター1")
        resultList.size.shouldBe 1
    }

    and "id は 1、point は 10 になるはず", {
        resultList[0].id.shouldBe 1
        resultList[0].point.shouldBe 10
    }
}

Java クラスは以下の通り。

DataDao.java ファイル
package sample;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class DataDao {

    private Connection con;

    public DataDao(Connection con) {
        this.con = con;
    }

    public List<Data> searchWithName(String name) {
        ArrayList<Data> result = new ArrayList<Data>();

        try {
            PreparedStatement ps = this.con.prepareStatement("select * from data where name=?");
            ps.setString(1, name);

            ResultSet rs = ps.executeQuery();

            while (rs.next()) {
                Data data = new Data();
                data.id = rs.getInt("id");
                data.name = rs.getString("name");
                data.point = rs.getInt("point");

                result.add(data);
            }
        }
        catch (SQLException ex) {
        }

        return result;
    }
}
Data.java ファイル
package sample;

public class Data {
    public int id;
    public String name;
    public int point;
}

easyb 実行

Gant を使って easyb を実行。
src ディレクトリに Java ソースファイル、spec ディレクトリに easyb ソースファイルを配置している。

build.gant ファイル
srcDir = "src"
destDir = "dest"
specDir = "spec"

includeTargets << gant.targets.Clean
cleanDirectory << destDir

target("default": null) {

    path(id: "project.classpath") {
        pathelement(path: "$destDir")

        fileset(dir: "c:/easyb-0.9") {
            include(name: "**/*.jar")
        }

        fileset(dir: "c:/easyb-dbunit-plugin-0.9") {
            include(name: "**/*.jar")
        }

        //Grails 内の HSQLDB を使用
        fileset(dir: "c:/grails-1.0.3/lib") {
            include(name: "**/*.jar")
        }
    }

    taskdef(name: "easyb", classname: "org.disco.easyb.ant.BehaviorRunnerTask") {
        classpath(refid: "project.classpath")
    }

    mkdir(dir: "$destDir")

    javac(srcdir: "$srcDir", destdir: "$destDir") {
        classpath(refid: "project.classpath")
    }

    easyb {
        classpath(refid: "project.classpath")
        behaviors(dir: "$specDir") {
            include(name: "**/*Story.groovy")
            include(name: "**/*.story")
            include(name: "**/*Specification.groovy")
            include(name: "**/*.specification")
        }
    }
}
実行結果
>gant
    ・・・
    [easyb] easyb is preparing to process 1 file(s)
    [easyb] Running data scenario story story (dataDao.story)
    [easyb] Scenarios run: 1, Failures: 0, Pending: 0, Time Elapsed: 1.332 sec
    [easyb] 1 behavior run with no failures
    [easyb] easyb execution passed