はじめに
SAStrutsなどSeasarベースのテストケースを作る時にS2JUnit4を使っているのですが、最近知ったSpockは簡潔に書くことができるので混ぜて使えないか試行錯誤していました。しかし、いくつか問題があり単純に混ぜることができませんでした。
そこでSpockの機能拡張を利用してS2JUnit4を取り込んだspock-seasarを作りました。
Spock Framework - Seasar2 Module
サンプル
SAStrutsとJSONで作ったJSONサンプルアプリのテストケースAddActionTest.javaをspock-seasarを使って書き換えてみました。
spock-seasarを使うための設定は、テストクラスに@Seasar2Support
アノテーションを付ける事だけです。
ここでresponse
とaddAction
はS2JUnit4と同様に自動フィールドバインディングされています。
尚、s2junit4.dicon
などを含んだファイル一式はsample-sastruts-json-webappsを参照してください。
package sample.sastruts.json.webapps.action
import org.seasar.framework.mock.servlet.MockHttpServletResponse
import org.shiena.seasar.Seasar2Support
import spock.lang.Specification
import spock.lang.Unroll
import javax.servlet.http.HttpServletResponse
@Seasar2Support
class AddActionSpec extends Specification {
HttpServletResponse response
AddAction addAction
@Unroll
def '#a1 + #a2 = #json'() {
setup:
addAction.addForm.with {
arg1 = a1
arg2 = a2
}
when:
def result = addAction.submit()
def mockHttpServletResponse = response as MockHttpServletResponse
then:
result == null
mockHttpServletResponse.contentType == 'application/json; charset=UTF-8'
new String(mockHttpServletResponse.responseBytes, 'UTF-8') == json
where:
a1 | a2
'1' | '2'
'-3' | '2'
'99999999999' | '1'
'1' | '99999999999'
'-9999999999' | '1'
'1' | '-9999999999'
'foobar' | '1'
'1' | 'foobar'
null | '1'
'1' | null
json << [
'{"result":3,"messages":null}',
'{"result":-1,"messages":null}',
'{"result":null,"messages":["numeric value out of bounds (<9 digits>.<0 digits> expected)"]}',
'{"result":null,"messages":["numeric value out of bounds (<9 digits>.<0 digits> expected)"]}',
'{"result":null,"messages":["numeric value out of bounds (<9 digits>.<0 digits> expected)"]}',
'{"result":null,"messages":["numeric value out of bounds (<9 digits>.<0 digits> expected)"]}',
'{"result":null,"messages":["numeric value out of bounds (<9 digits>.<0 digits> expected)"]}',
'{"result":null,"messages":["numeric value out of bounds (<9 digits>.<0 digits> expected)"]}',
'{"result":null,"messages":["may not be empty"]}',
'{"result":null,"messages":["may not be empty"]}',
]
}
}
spock-seasarの機能
基本的にS2JUnit4と同じですが、追加および削除した機能があります。
追加した機能
Spockはgroovyで作られているのでTestContext.getMethodName()
はテストメソッド名ではなく、$spock_feature_0_0のような意図しない文字列を返却します。そのため、テストケースに記述したメソッド名を返却するTestContextの実装を用意しました。
org.shiena.seasar.S2SpockInternalTestContextImpl
InternalTestContextImplを継承したTestContextです。
- getFeatureName() - Unroll前のテストメソッド名を返却します。
- getIterationName() - Unroll後のテストメソッド名を返却します。
org.shiena.seasar.S2SpockSimpleInternalTestContext
SimpleInternalTestContextを継承したTestContextです。
- getFeatureName() - Unroll前のテストメソッド名を返却します。
- getIterationName() - Unroll後のテストメソッド名を返却します。
削除した機能
SpockとS2JUnit4で重複した機能やSpockで使いにくい機能は削除しました。
- メソッドの命名規則
-
@Prerequisite
アノテーション -
@Mock
アノテーション -
@Mocks
アノテーション -
@EasyMock
アノテーション -
@PostBindFields
アノテーション -
@PreUnbindFields
アノテーション -
s2junit4config.dicon
を使ったS2JUnit4のカスタマイズ
処理の順序
以下に、spock-seasarの処理順序と取り込んだ機能を太字で示します。
たとえば、自動フィールドバインディングはsetup()
の後なので、フィールドを参照できるのはテストメソッドのsetup
ブロック以降です。
- setupSpec()
- 各テストメソッドの繰り返し開始
- テスト用コンテナの初期化とTestContextのバインディング
- setup()
- 自動フィールドバインディング
- テストメソッド実行
- 自動フィールドバインディングしたフィールドの破棄
- cleanup()
- テスト用コンテナの破棄
- 各テストメソッドの繰り返し終了
- cleanupSpec()
使い方
gradleの場合
repositories {
maven {
url 'https://bitbucket.org/shiena/mvn-repo/raw/tip/'
}
}
dependencies {
testCompile 'org.shiena:spock-seasar:0.0.1'
}
mavenの場合
<repositories>
<repository>
<url>https://bitbucket.org/shiena/mvn-repo/raw/tip/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.shiena</groupId>
<artifactId>spock-seasar</artifactId>
<version>0.0.1</version>
<scope>test</scope>
</dependency>
</dependencies>
注意点
残念ながらSpockとS2JUnit4は必要なJUnitのバージョンが異なるので混ぜて使うことができません。
これが最初に書いたできなかった理由です。どちらかのバージョンに合わせても、もう片方でエラーが起きます。
- SpockはJUnit4.7以上が必要です。
- S2JUnit4はJUnit4.4が必要です。
まとめ
Spockの機能拡張の作り方はSeasar2やSpring Frameworkのインターセプターと似た印象でした。
JUnitで共通処理を用意するときは親クラスを作ったりしましたが、Spockでは機能拡張で作ることもできそうです。