SAStrutsを学ぶ – まずはS2Junit4でServiceをUnitテスト
藤原のような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連打はした方がいいかも。
僕について
Dai Fujihara
A hero can be anyone.
藤原大はマネージャでありアジャイル実践者だ。そして、プロジェクトリーダー、チェンジ・エージェント、アジャイルコーチ、トレーナーでもある。彼はまたRedmine、Jenkinsといった開発を支援するツール環境の整備や、アジャイル開発を活用した創造的なソフトウェア開発の支援を行っている。さらに、趣味は沖縄離島巡りらしい。
ここ最近の人気
永久保存の本
Venkat Subramaniam (著), Andy Hunt (著), 木下 史彦 (監訳), 角谷 信太郎 (監訳)
アジャイルな習慣とは一体何なのか?本書ではプラクティスを交えながら、その姿勢を読者に問いかけている。世代や役割をこえて色褪せない「アジャイル」に対する良書。Amazonレビュー
Mike Cohn (著), マイク コーン (著), 安井 力 (翻訳), 角谷 信太郎 (翻訳)
採用した現在のタイトルは、見積りや計画づくりといったプロセスを、アジャイルに進めなければならないと謳っているのだ。見積りと計画づくりがアジャイルでないのに、プロジェクトがアジャイルであるということはありえない。(イントロダクションより)
Jonathan Rasmusson (著), 西村 直人 (翻訳), 角谷 信太郎 (翻訳)
アジャイルサムライ―それはソフトウェアを顧客に届ける猛々しきプロフェッショナルだ。本書では、圧倒的なアジャイルプロジェクトの姿を見せる。2011年爆発的にヒットしたアジャイル開発に情熱を持つエンジニアに届けたい本。タグ
Agile ant Apache bash Eclipse GlassFish install Java Javascript kobo Linux log4j Management Maven Open Source PHP Pukiwiki Python Redmine Ruby Ruby on Rails Scrum Spring Struts Struts2 Subversion Test Tomcat Trac VBA Web WebDriver WebLogic Windows WordPress 働く 勉強会 嫁(ベータ) 思い出し笑う 我思う 旅する 映画/ドラマ 英語を話す 読むと聞く 過去を語るアーカイブ















