S2EJB3Unitを使ったpersistの検証
IDを自動生成する設定でEntityをpersistした場合、生成されるIDを期待値としてあらかじめExcelに用意できないのでS2Unitのreloadメソッドを使ってテストができないですね、という話が Seasar Conference 2006 Spring のときにありました。(S2Unitのreloadメソッドはプライマリキーを使ってDBから値をリロードします。)
S2EJB3Unitで対策を考えてみました。EntityをpersistしてEntityManagerをflushすればEntityにIDが書き戻されるはずなのでこの値を使ってリロードするようにしてみました。こんな感じでどうでしょう。
まず、期待値と結果値をExcelで用意します(DEPARTMENT - EMPLOYEE - ADDRESS といったテーブル構造を想定してます)。[]でくくったのはExcelのシート名です。ポイントは期待値のシートにIDのカラムを含めないことです(単にIDは比較しないということです)。
insertEmployeePrepare.xls
[ADDRESS]
ID | CITY |
---|---|
3 | 京都 |
[DEPARTMENT]
ID | DEPARTMENTNAME |
---|---|
2 | 経理 |
insertEmployeeResult.xls
[EMPLOYEE]
EMPLOYEENAME | SALARY | DEPT_ID | ADDRESS_ID |
---|---|---|---|
XXX | 3000 | 2 | 3 |
次に、テストメソッドを書きます。ポイントはreloadAsDataSetメソッドを使ってエンティティをDataSetとして再取得するところです。EntityManagerのflushはreloadAsDataSetメソッドの中で実行してます。
public class EmployeeTest extends S2EJB3TestCase {
@Rollback
public void testInsertEmployee() {
readXlsWriteDb("insertEmployeePrepare.xls");
DataSet expected = readXls("insertEmployeeResult.xls");
Address address = getEntityManager().find(Address.class, new Long(3));
Department department = getEntityManager().find(Department.class, new Long(2));
Employee employee = new Employee();
employee.setEmployeeName("XXX");
employee.setSalary(3000);
employee.setAddress(address);
employee.setDepartment(department);
getEntityManager().persist(employee);
assertEquals("1", expected, reloadAsDataSet(employee));
}
}
ひとつのテーブルに対して複数件insertされる場合の検証は特に考えていません(テストには必要ないと思いました)。
ただ、SecondaryTable、Joined Sublcassなどを使ったエンティティをpersistすると同時に複数テーブルにinsertが実行されることがありますが、これを検証したいことはあると思います。その場合は期待値のExcelシートを検証したいテーブルの数だけ用意しておけばOKです。カスケードで関連先のエンティティも同時にpersistされることを検証したい場合は reloadAsDataSet(employee, true) としてリレーションシップも辿ることを示して、期待値のExcelシートをテーブルの数だけ用意します。
(追記)
reloadAsDataSet なんていうメソッド作らなくても EntityManager を flush した後に エンティティを refresh すればいいのかも。DBにinsertしたデータをJDBC APIで取得するかJPAで取得するかのちがいなんですよね。
id:koichikさん、id:da-yoshiさん、つっこみどころがあったらよろしくお願いします。