Kotlin Spek で Groovy Spock where のようなテスト

ついに Kotlin 1.0 がリリースされました。
テストや Spec を書こうと思った場合、Groovy には [Spock](http://spockframework.github.io/spock/docs/1.0/index.html) という強力なフレームワークがありました。
Kotlin では [Spek](http://jetbrains.github.io/spek/) を使用します。

# 環境

- Maven 3.3.3
- Java 1.8.0_45
- Kotlin 1.0.0
- Spek 0.1.195

```
$ mvn --version
Apache Maven 3.3.3 (7994120775791599e205a5524ec3e0dfe41d4a06; 2015-04-22T20:57:37+09:00)
Maven home: /usr/local/Cellar/maven/3.3.3/libexec
Java version: 1.8.0_45, vendor: Oracle Corporation
Java home: /Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/jre
Default locale: ja_JP, platform encoding: UTF-8
OS name: "mac os x", version: "10.10.3", arch: "x86_64", family: "mac"
```

# Spek

Spek は非常にシンプルなテスティングフレームワークで、Spock とは異なり、`given` `on` `it` の3種類のブロックしか出てきません。
それぞれには以下の役割があります。

| ブロック | 役割        |
|---------|-------------|
| given   | セットアップ。テストターゲットのインスタンス生成や、パラメタ、期待値の準備など。 |
| on      | アクション。テストターゲットの実行。 |
| it      | アサーション。 |

より具体的なサンプルは Spek のドキュメントをどうぞ。
http://spekframework.org/docs/latest/

# where

さて、ここで問題に気付きます。
Spek には、Spock でテストを見通し良くするのに貢献していた `where` に相当するブロックがありません。

存在しないからには、なにか理由があるはずです。
考えた結果、おそらく その答えは Kotlin の表現力の高さにあります。
以下、FizzBuzz を例にとって、`where` に相当するコードを Kotlin、Spek で記述してみます。

全てのコード。
https://github.com/yo1000/fizzbuzz-kotlin.git

テストターゲット。

```kotlin:FizzBuzz.kt
class FizzBuzz() {
    fun fizz(value: Int): String {
        return if (value % 3 == 0) "fizz" else ""
    }

    fun buzz(value: Int): String {
        return if (value % 5 == 0) "buzz" else ""
    }

    fun fizzBuzz(value: Int): String {
        val builder = StringBuilder(fizz(value)).append(buzz(value))
        return if (builder.isEmpty()) value.toString() else builder.toString()
    }
}
```

テスト。

```kotlin:FizzBuzzTest.kt
import org.jetbrains.spek.api.Spek
import kotlin.test.assertEquals

data class Params(val value: Int)
data class Expects(val fizz: String, val buzz: String, val fizzBuzz: String)

class FizzBuzzTest: Spek() {
    init {
        given("fizzBuzz") {
            val fizzBuzz = FizzBuzz()

            listOf(
                    Params( 3) to Expects("fizz" , ""    , "fizz"    ),
                    Params( 5) to Expects(""     , "buzz", "buzz"    ),
                    Params(15) to Expects("fizz" , "buzz", "fizzbuzz"),
                    Params( 4) to Expects(""     , ""    , "4"       )
            ).forEach {
                val (param, expect) = it

                on("fizzbuzz param=${param.value}") {
                    val fizz = fizzBuzz.fizz(param.value)
                    val buzz = fizzBuzz.buzz(param.value)
                    val fizzBuzz = fizzBuzz.fizzBuzz(param.value)

                    it ("${expect.fizz}=${fizz}") {
                        assertEquals(expect.fizz, fizz)
                    }
                    it ("${expect.buzz}=${buzz}") {
                        assertEquals(expect.buzz, buzz)
                    }
                    it ("${expect.fizzBuzz}=${fizzBuzz}") {
                        assertEquals(expect.fizzBuzz, fizzBuzz)
                    }
                }
            }
        }
    }
}
```

テスト結果。

<img width="643" alt="スクリーンショット 2016-02-28 0.00.11.png" src="https://qiita-image-store.s3.amazonaws.com/0/47993/ac7a5361-c1e9-3676-6d46-1971f4904019.png">

Kotlin の [`data`](https://kotlinlang.org/docs/reference/data-classes.html) [`listOf`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/list-of.html) [`to`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/to.html) [`val (a, b) = p`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-pair/) を使用することで、かなり `where` 表現に近づけたのではないかと思います。
この表現力の高さゆえ Spek では、あえて `where` に相当するブロックが用意されていないのではないかと思いました。