Help us understand the problem. What is going on with this article?

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

More than 5 years have passed since last update.

はじめに

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を参照してください。

AddActionSpec.groovy
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の場合

build.gradle
repositories {
    maven {
        url 'https://bitbucket.org/shiena/mvn-repo/raw/tip/'
    }
}

dependencies {
    testCompile 'org.shiena:spock-seasar:0.0.1'
}

mavenの場合

pom.xml
<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では機能拡張で作ることもできそうです。

参考

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away