Seasar2 でテストを書き始めて少し経ちはじめましたが、 S2JUnit4 は個人的に未開拓だったので使ってみました。
使ってみてメリットと感じたものは
これまでは super class のメソッドで呼び出せていたものが、 static import しないとコード量が増えてしまうのがデメリットぐらいでしょうか。
まだまだ業務でも S2TestCase を使って書いている数は少ないのですが、メソッド名に Tx をつけ忘れて実行して orz となることもありました。(癖的なものなんでしょうが)自動的にロールバックしてくれるだけで考える必要もなくなり、開発者の負担が減ります。それから規約で自動的に期待値のファイルを読み込んでくれる。クラス単位、メソッド単位でテストデータの読み込みを切り替えられるのもいいですね。
以上感想でした。
後は適当に書いたものを貼り付けておきます。 Web アプリケーションの場合は SimpleInternalTestContext でなく InternalTestContextImpl にしてあげる必要があります。(jtaEnabled もいらない)
s2junit4.dicon は下みたいな感じです。 src/test/resources 直下に置きました。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN" "http://www.seasar.org/dtd/components24.dtd"> <components namespace="s2junit4"> <include path="app.dicon" /> <component name="context" class="org.seasar.framework.unit.impl.SimpleInternalTestContext"> <property name="jtaEnabled">true</property> <property name="preparationType">@org.seasar.framework.unit.PreparationType@ALL_REPLACE</property> </component> <component class="org.seasar.framework.unit.impl.SimpleDataAccessor" /> <component class="org.seasar.framework.unit.impl.ConfigFileIncluderImpl"> <initMethod name="addConfigFile"> <arg>context.testClassShortName + ".dicon"</arg> </initMethod> </component> <component class="org.seasar.framework.unit.impl.TestDataPreparerImpl"> <initMethod name="addTestDataXlsPath"> <arg> context.testClassShortName + "_" + context.testMethodName + ".xls" </arg> </initMethod> <initMethod name="addTestDataXlsPath"> <arg>context.testClassShortName + ".xls"</arg> </initMethod> </component> <component class="org.seasar.framework.unit.impl.ExpectedDataReaderImpl"> <initMethod name="addExpectedDataXlsPath"> <arg> context.testClassShortName + "_" + context.testMethodName + "_Expected" + ".xls" </arg> </initMethod> </component> </components>
サンプルから変更したものとして app.dicon を include させました。それから EJB3 は使っていないので SimpleInternalTestContext を使っています。ただ jtaEnabled が無効になっていて、テスト時にデータベースの読み込みを開始してくれないので true にします。それから 1 メソッドおきに readXlsAllReplaceDb を実行したいので preparationType にも ALL_REPLACE を指定します。
このあたりはドキュメントに書いてあります。
Seasar - DI Container with AOP -
これで src/test/java/example/service/impl 以下のサービスクラス、メソッドと、 src/test/resources/example/service/impl 以下の Excel ファイルが結びつけられる寸法になるわけです。(この例では UserServiceImplTest.xls, UserServiceImplTest_testInsert_Expected.xls を用意してデータを書いておきます)
実際のテストコードはこんな感じですっきりしています。
package example.service.impl;
import static org.seasar.framework.unit.S2Assert.assertEquals;
import org.junit.runner.RunWith;
import org.seasar.framework.unit.DataAccessor;
import org.seasar.framework.unit.Seasar2;
import org.seasar.framework.unit.TestContext;
import example.entity.Account;
import example.service.AccountService;
@RunWith(Seasar2.class)
public class UserServiceImplTest {
private DataAccessor accessor;
private TestContext ctx;
private UserService userService;
@Test
public void testInsert() {
User user = new User();
user.setName("ussy");
user.setPassword("ussy");
user.setMailAddress("ussy@example.com");
userService.insert(user);
assertEquals(ctx.getExpected().getTable("user"), accessor.readDbByTable("user"));
}
}
今回はテーブルの中身が完全に思ったとおりになっていることを確認するために、 DataTable の比較を行っています。ただこれだと ID が自動採番によってテストを行うたびに変わってしまうので、考慮しないといけないなあという感じです。
[追記]
Web アプリケーションのテストを行う場合は SimpleInternalTestContext でなく InternalTestContextImpl にしてあげる必要があります。 ComponentDeployerFactory.Provider の createRequestComponentDeployer で UnsupportedOperationException が発生します。
EJB3 を使わない場合は pom.xml の scope をいじっておくとよいです。
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-ejb_3.0_spec</artifactId>
<version>1.0</version>
<scope>test</scope>
</dependency>
小一時間悩んだのですが、標準設定からいじった自分への罰ですね。でもこんな失敗から少しずつ内部の仕組みが分かっていくのも楽しいです。(忙しくなければ)