藤原のようなStruts1.xを使っていた世代は、DIを覚えなきゃやばいと感じたので、SAStrutsを勉強している。
どうも、最近のJavaフレームワークをみていると、Struts2は死にかけていて、スタンダートとしてSpring。国内なら国産のSeaserみたい。Google Guiceも、生まれたてなのに結構奮闘している。
まずはSAStrutsをと思い、その中でも業務にかかわってきそうなUnitテストの動きを調べてみる。
テストネタ
まずは、1分でWebアプリを作れるEclipseプラグイン「Dolteng」を読みながら、H2データベースを使って、実際にSAStrutsを動かしてみる。
ここで自動作成されたクラスはAction、Service、Entity、Formとあり、DB接続やWeb画面まであるので、これらに対して単体テストをおこなってみる。
単体テストを作ってみる
S2JUnit4のページを読んだが、すんなりできなかった部分があったので、自分のやった手順をまとめる。
まず、1分でWebアプリを作れるEclipseプラグイン「Dolteng」ではDeptというテーブルとEmpというテーブルがありそれぞれにサンプルデータが少し入っている。今回はDeptServiceのクラスを作る。このクラスはfindByIdでIDに紐づいたデータを取ってくるServiceクラス。
まず、s2junit4pluginのページを参考にテストケースクラスとdiconファイルを作成する。テストケースクラスである「DeptServiceTest 」にはテストを実装する。
package com.daipresents.sastruts.service; import static org.junit.Assert.assertNull; import static org.seasar.framework.unit.S2Assert.assertEquals; import org.junit.Test; import org.junit.runner.RunWith; import org.seasar.framework.unit.Seasar2; import org.seasar.framework.unit.TestContext; import com.daipresents.sastruts.entity.Dept; @RunWith(Seasar2.class) public class DeptServiceTest { private TestContext ctx; private DeptService deptService; /** * {@link com.daipresents.sastruts.service.DeptService#findById(java.lang.Long)} のためのテスト・メソッド。 */ @Test public void testFindById() { Dept dept = deptService.findById(new Long(90000)); assertNull(ctx.getTestMethodName() + ":データが存在しない場合", dept); dept = deptService.findById(new Long(90001)); assertEquals(ctx.getTestMethodName() + ":データが存在する場合", ctx.getExpected(), dept); } }
diconは何も書かなくてよかった。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN" "http://www.seasar.org/dtd/components24.dtd"> <components></components>
ただ、「<include path=”app.dicon”/>」を書かないとS2JDBC + S2JUnit4でハマると同じ現象がでたんだけど気のせいかもしれない。Seasar S2JUnit4 – @//メモでは書いてあるんだけど、消しても動いてしまった。
「src/test/resources/s2junit4.dicon」に
<component class="org.seasar.framework.unit.impl.ConfigFileIncluderImpl"> <initMethod name="addConfigFile"> <arg>"app.dicon"</arg> </initMethod> <initMethod name="addConfigFile"> <arg>context.testClassShortName + ".dicon"</arg> </initMethod> </component>
と書かれているので、消しても動くんだと思うけど。どっちだろうね。
で、テストと同じ場所に「DeptServiceTesttestFindById.xls」と「DeptServiceTesttestFindById_Expected.xls」を作る。
前者はテスト時の初期データとなり、後者は予想するデータとなる。
今回テストするクラスはデータを参照するだけなので、両ファイルとも同じ内容になる。
データは以下のような感じ。必須の値はすべて埋めないと、Insertしたときにエラーとなる。
ここまできたら、H2データベースを起動、Tomcatを起動して、DeptServiceTestをEclipseで開いて「Ctrl+0」を押せばテストが始まる。
Eclipseにでるログはこんな感じです。
設定ファイル(com/daipresents/sastruts/service/DeptServiceTest.dicon)をインクルードします S2Containerを作成します。path=com/daipresents/sastruts/service/DeptServiceTest.dicon S2Containerを作成しました。path=com/daipresents/sastruts/service/DeptServiceTest.dicon クラス(com.daipresents.sastruts.service.DeptService[deptService])のコンポーネント定義を登録します トランザクションを開始しました。tx=[FormatId=4360, GlobalId=1260108703621/0, BranchId=] Excelファイル(com/daipresents/sastruts/service/DeptServiceTest_testFindById.xls)の値をデータベースに追加します 物理的なコネクションを取得しました 論理的なコネクションを取得しました。tx=[FormatId=4360, GlobalId=1260108703621/0, BranchId=] 論理的なコネクションを閉じました。tx=[FormatId=4360, GlobalId=1260108703621/0, BranchId=] 論理的なコネクションを取得しました。tx=[FormatId=4360, GlobalId=1260108703621/0, BranchId=] INSERT INTO dept (ID, DEPT_NO, DEPT_NAME, LOC, VERSION_NO) VALUES (90001, 50, '総務課', '大阪', 1) 論理的なコネクションを閉じました。tx=[FormatId=4360, GlobalId=1260108703621/0, BranchId=] 論理的なコネクションを取得しました。tx=[FormatId=4360, GlobalId=1260108703621/0, BranchId=] INSERT INTO dept (ID, DEPT_NO, DEPT_NAME, LOC, VERSION_NO) VALUES (90002, 60, '人事課', '名古屋', 1) 論理的なコネクションを閉じました。tx=[FormatId=4360, GlobalId=1260108703621/0, BranchId=] BEGIN com.daipresents.sastruts.service.DeptService#findById(90000) select T1_.ID as C1_, T1_.DEPT_NO as C2_, T1_.DEPT_NAME as C3_, T1_.LOC as C4_, T1_.VERSION_NO as C5_ from DEPT T1_ where T1_.ID = 90000 論理的なコネクションを取得しました。tx=[FormatId=4360, GlobalId=1260108703621/0, BranchId=] END com.daipresents.sastruts.service.DeptService#findById(90000) : null BEGIN com.daipresents.sastruts.service.DeptService#findById(90001) select T1_.ID as C1_, T1_.DEPT_NO as C2_, T1_.DEPT_NAME as C3_, T1_.LOC as C4_, T1_.VERSION_NO as C5_ from DEPT T1_ where T1_.ID = 90001 END com.daipresents.sastruts.service.DeptService#findById(90001) : com.daipresents.sastruts.entity.Dept@19ea173 Excelファイル(com/daipresents/sastruts/service/DeptServiceTest_testFindById_Expected.xls)を期待値として読み込みます トランザクションをロールバックしました。tx=[FormatId=4360, GlobalId=1260108703621/0, BranchId=] 論理的なコネクションを閉じました。tx=[FormatId=4360, GlobalId=1260108703621/0, BranchId=] 物理的なコネクションを閉じました 環境変数#Envにファイル(env.txt)から値(ct)が設定されました
データを取り込んで、それに対してテスト。結果を予期したデータと比較している。
まとめ
DBアクセスしているServiceクラスの単体テストは成功。DBUnitみたいなもんかということで、DIのテストという感じがしなかった。
また、今回の場合、findByIdでデータを取ってくるが、このメソッドだと、データが存在すれば1レコードがかえってきて、存在しなければnullがかえってくる。
よって、予期するデータに複数件レコードをいれてしまうと、「レコードが2つもあるよ!」と怒られる。
初期データは使いまわせる気がするが、予期するデータはテストメソッドごとに必要になる。
ここからActionとかもテストしてみる予定だけど、S2JUnitってはやってないせいか、Googleの検索結果が少ないのが気になる。
余談
Excel2007をEclipseから開いて保存するとEclipseが固まりPCもブルーバックになったので、みんな気をつけろ!
また、Excelをエクスプローラから開いて編集しても、Eclipseでそのファイルを更新しないと、テストに反映されないみたい。F5連打はした方がいいかも。