DEV Community

KOGA Mitsuhiro
KOGA Mitsuhiro

Posted on • Originally published at qiita.com

SpockとS2JUnit4を混在できないのでspock-seasarを作った

はじめに

SAStrutsなどSeasarベースのテストケースを作る時にS2JUnit4を使っているのですが、最近知ったSpockは簡潔に書くことができるので混ぜて使えないか試行錯誤していました。しかし、いくつか問題があり単純に混ぜることができませんでした。
そこでSpockの機能拡張を利用してS2JUnit4を取り込んだspock-seasarを作りました。

Spock Framework - Seasar2 Module

サンプル

SAStrutsとJSONで作ったJSONサンプルアプリのテストケースAddActionTest.javaをspock-seasarを使って書き換えてみました。
spock-seasarを使うための設定は、テストクラスに@Seasar2Supportアノテーションを付ける事だけです。
ここでresponseaddActionは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ブロック以降です。

  1. setupSpec()
  2. 各テストメソッドの繰り返し開始
  3. テスト用コンテナの初期化とTestContextのバインディング
  4. setup()
  5. 自動フィールドバインディング
  6. テストメソッド実行
  7. 自動フィールドバインディングしたフィールドの破棄
  8. cleanup()
  9. テスト用コンテナの破棄
  10. 各テストメソッドの繰り返し終了
  11. 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の機能拡張の作り方はSeasar2やSpring Frameworkのインターセプターと似た印象でした。
JUnitで共通処理を用意するときは親クラスを作ったりしましたが、Spockでは機能拡張で作ることもできそうです。

参考

Top comments (0)