のえら

技術備忘とかメモとか.間違いはつっこんでいただきたい所存.

Spockをちょっと触ったので覚え書き

初めてGroovySpockを触ったので色々と覚え書き。

動作確認は Spock Web Console を使用。
https://meetspock.appspot.com/

基本的な検証の例と出力結果

  • フィーチャーメソッドの名称は自由
  • フィーチャーブロックにはコメントも書ける(出力はされない)
  • setup(given) -> expect or when, then [-> expect or when, then] -> cleanup (whereは後述)
  • when と then はセットで使用する、一つのフィーチャーメソッド内に複数書ける
サンプルコード
import spock.lang.*

class SampleSpec extends Specification {
    def 'given, when, then'() {
        given:
        def amount = 1000
        when: '合計値に0.5をかけた場合'
        def actual = amount * 0.5
        then: '1000が返ること'
        actual == 1000
    }

    def 'only expect'() {
        expect:
        Math.max(10, 3) == 3
    }

    def 'setup, cleanup'() {
        setup:
        def numbers = [1, 3, 4, 0]

        expect:
        numbers.isEmpty()

        cleanup:
        numbers.clear()
    }
}
実行結果

- maximum of two numbers, 0 or 0
- given, when, then FAILED

Condition not satisfied:

actual == 1000
| |
500.0 false

at SampleSpec.given, when, then(Script1.groovy:22)

- only expect FAILED

Condition not satisfied:

Math.max(10, 3) == 3
| |
10 false

at SampleSpec.only expect(Script1.groovy:27)

- setup, cleanup

whereブロックの話

同じ内容のテストをテストする値を変更して実行したい場合に使える。

  • Unrollアノテーションはwhereブロックの実行結果を行ごとで出してくれる(whereブロックの変数が使用できる)
  • フィーチャーメソッドの引数は任意、それぞれの引数の型を明示的に指定することもできる
  • whereブロックはフィーチャーメソッドの中身をまるっと実行する
サンプルコード
import spock.lang.*

class SampleSpec extends Specification {
    @Unroll
    def "maximum of two numbers, #first or #second"(int first, int second, int expected) {
        expect:
        Math.max(first, second) == expected

        where:
        first | second || expected
        1 | 3 || 3
        7 | 4 || 4  // ここは失敗する
        0 | 0 || 0
    }
}
実行結果

SampleSpec
- maximum of two numbers, 1 or 3
- maximum of two numbers, 7 or 4 FAILED

Condition not satisfied:

Math.max(first, second) == expected
| | | | |
7 7 4 | 4
false

at SampleSpec.maximum of two numbers, #first or #second(Script1.groovy:7)

- maximum of two numbers, 0 or 0

whereブロックの話その2

  • 何度目かは #iterationCount で取得できる(フィーチャーメソッド名の中だけで使用可能?)
  • テーブル形式とパイプ形式がある、後者はイテレーションが使えるオブジェクトならなんでも呼び出せる、外部リソースを使うようなテストで使用する?
サンプルコード
import spock.lang.*

class SampleSpec extends Specification {
    @Unroll
    def "like a table(#a, #b)[#iterationCount]"() {
        expect:
        Math.max(a, b) == b
        where:
        a | b
        1 | 7
        2 | 8
        3 | 9
    }

    @Unroll
    def "pipe(#a, #b)[#iterationCount]"() {
        expect:
        Math.max(a, b) == b
        where:
        a << [123]
        b << [789]
    }
}
実行結果

SampleSpec
- like a table(1, 7)[0]
- like a table(2, 8)[1]
- like a table(3, 9)[2]
- pipe(1, 7)[0]
- pipe(2, 8)[1]
- pipe(3, 9)[2]

フィクスチャーメソッド

テスト全体とフィーチャーメソッドの前後に実行される。
RSpec でいう before(:each), before(:all), after(:each), after(:all) のようなもの。

サンプルコード
import spock.lang.*
 
class MyFirstSpec extends Specification {
	def setupSpec() {
		println('call setupSpec')
	}
 
	def setup() {
		println('call setup')
	}

	def cleanup() {
     		println('call cleanup')
   	}
 
   	def cleanupSpec() {
     		println('call cleanupSpec')
   	}
 
   	def 'test1'() {
     		println('call test1')
     		expect:
     		assert true
   	}

   	def 'test2'() {
   		println('call test2')
   		expect:
     		assert true
   	}

	def 'test3'() {
        		println('call test3')
        		expect:
        		assert true
        		where:
        		a | b
        		1 | 2
        		3 | 4
    	}
}
実行結果(外部出力)

call setupSpec
call setup
call test1
call cleanup
call setup
call test2
call cleanup
call setup
call test3
call cleanup
call setup
call test3
call cleanup
call cleanupSpec