Spockを始めるのに最低限必要なGroovyの基本知識

# はじめに
「プロダクトコードはJavaだけど、Spockを使ってテストを書いてみたい...だけどGroovyを習得するのが大変そう」  
と思っている方がいるかもしれません（筆者がそうでした）。たしかにGroovy自体は奥の深い言語なのですが、とりあえずSpockでテストを書く分には基本的なところだけ押さえておけば不自由しません。  
というわけで、実際にJavaのプロジェクトにSpockを導入してみて、まずはこれだけ押さえておけばSpockを始められる、という基本をまとめてみました。

# 基本のキ
## アサート
この後のサンプルソースで出てくるので先に説明します。

* 必ず真になるべき条件の表明は`assert 真と評価されるべき式`で記述します。
* Groovyでは文末のセミコロン`;`は省略できます。

```groovy
assert 1 < 2
```

## クラスの定義
* Javaと同じく`extends`でクラス継承、`implements`でインタフェース継承です。
* アクセス修飾子はデフォルトが`public`です。Groovyの中ではpublicもprivateも差がないので、基本アクセス修飾子は書かなくてよいです。

```groovy
class SomeSpec extends Specification {
}
```

## メソッドの定義
* Javaと同じように書くこともできますし、引数・戻り値の型名を省略して書くことも可能です。
* 戻り値の型名を省略する場合は`def`キーワードが必須です。
* メソッドで最後に評価された式が暗黙的に返されるため、途中のリターンでなければ`return`を省略できます。
* アクセス修飾子はデフォルトが`public`です。Groovyの中ではpublicもprivateも差がないので、基本アクセス修飾子は書かなくてよいです。

```groovy
// 型名を明示
int increment(int arg) {
    return arg + 1
}

// 型名を省略
def increment2(arg) {
    arg + 1
}
```

## インスタンス生成、変数への代入
* インスタンスの生成はJavaと同じく`new`演算子を使います。
* 変数は`def`で定義します。
* 型推論が働くので左辺に型名は不要です（明示することも可能です）。

```groovy
def pet = new Pet()
Pet pet2 = new Pet() //型を明示するならdefは不要
```

## インスタンス変数の定義（プロパティ）
* `def`または型名指定でインスタンス変数を定義します。
* 自動で`getter/setter`が生成されます。

```groovy
class Pet {
    String name
    def age
}
```

## プロパティアクセス
* 自動生成された`getter/setter`を明示的に利用することができます。
* インスタンス変数へのアクセスは`getter/setter`を使ったアクセスに変換されます。

```groovy
def pet = new Pet()

// 明示的なアクセサの利用
pet.setName("Pochi")
assert pet.getName() == "Pochi"

// 暗黙的なアクセサの利用
pet.age = 2
assert pet.age == 2
```

これはJavaオブジェクトに対するアクセスにも適用されます。以下のJavaクラスがあったとして、

```java
// Hoge.java
public class Hoge {
    private String name;
    public String getName() {
        return name + "!";
    }
    public void setName(String name) {
        //大文字変換
        this.name = name.toUpperCase();
    }
}
```

変数へのアクセスが実際には`getter/setter`経由のプロパティアクセスとなっていることがわかります。


```groovy
def hoge = new Hoge()
hoge.name = "fuga" // 実はhoge.setName
assert hoge.name == "FUGA!" // 実はhoge.getName
```

## 等値性と同一性
* Groovyの`==`はJavaの`equals`であり、値として等値であるかを評価します。
* 参照の同一性は`is`メソッドを使って評価します。
* アプリケーションの大半のケースでは等値性を問うので、プリミティブ型、参照型に関わらず`==`を使って比較すればOKです。

```groovy
def date1 = LocalDate.of(2020, 1, 1)
def date2 = LocalDate.of(2020, 1, 1)

assert date1 == date2 // 等値性
assert !date1.is(date2) // 同一性
```

# Truthy
* boolean型以外の方も（JavaScriptのような）真偽値判定ができます（if文の条件にも使えます）。

```groovy
assert 1 // 数値型：非ゼロは真
assert !0 // 数値型：ゼロは偽

assert "hoge" // 文字列型：非空文字列は真
assert !"" // 文字列型：空文字列は偽

assert new Pet() // オブジェクト型：非nullは真
def petNull
assert !petNull // オブジェクト型：nullは偽
```

# コレクション
## リテラル表記
* リストは`[]`の中にカンマ区切りで要素を列挙します。

```groovy
def emptyList = []
def list = [1, 2, 3]
```

* マップのリテラルはリストと似ていますが、`:`でキーと値を区切って列挙します。
* 文字列をキーとする場合、`""`で囲わなくてもOKです。
* enumの要素をキーに使う場合は括弧`()`で囲う必要があります。

```groovy
def emptyMap = [:]
def map1 = ["one": 1, "two": 2]
def map2 = [one:1, two: 2]
assert map1 == map2
def map3 = [(BloodTypes.A):"A型"]
```

* セットはリストと同じリテラル表記で、後ろに`as Set`を付けます。

```groovy
def emptySet = [] as Set
def set = [1, 2, 3] as Set
```

## 要素へのアクセス
* リストの要素は`[添字]`でアクセスできます。
* マップの要素は`[キー]`でアクセスできます。

```groovy
assert list[0] == 1
assert map2["one"] == 1
```

## Truthy

いずれのコレクション型も真偽判定に使えます。

```groovy
assert list // コレクション型：非emptyなら真
assert !emptyList // コレクション型：emptyなら偽
```

# クロージャ
クロージャはJavaでいうラムダ式にあたるものです。
Spockでクロージャを使うのは、Mockを使う場合やテスト対象のJavaメソッドが関数型インタフェースを引数に要求するときなど限られた場面だと思うので、この章は必要になる時まで飛ばしてもらっても大丈夫です。

## 引数が1個
* `{ 引数 -> 文 }` という形式でクロージャを定義します。
* 引数が1つの場合は省略可能で、その場合は`it`という引数が暗黙的に定義されます。

```groovy
def doubler = { x -> x * 2 }
assert doubler(1) == 2
// 暗黙のitを使用すれば以下のように書いても同じ
def doubler2 = { it * 2 }
assert doubler2(1) == 2
```

## 引数が0個
* 引数がないクロージャの見た目は`{}`で囲われたコードブロックです。
* GroovyのクロージャはJavaのラムダ式と違い、**外側の変数を変更できます**。

```groovy
def num = 0
def counter = { num++ }
counter()
assert num == 1
```

## 引数が複数個
* 引数が複数の場合、括弧で囲まずに引数リストを列挙します。

```groovy
def adder = { x, y -> x + y }
assert adder(1, 2)
```

## 複数の文からなるクロージャ
* クロージャのブロック内で改行して複数の文を記述できます。
* 1行で書きたければ`;`で文を区切ることも可能です。

```groovy
def doubleThenAddOne = {
    it = it * 2
    it + 1
}
assert doubleThenAddOne(2) == 5

def doubleThenAddOne2 = { it = it * 2; it + 1 }
assert doubleThenAddOne2(2) == 5
```

# Spockのテストケースを書く
ここまで学んだGroovyの基礎知識があれば、基本的なSpockのテストケースを書くことができます。

```groovy
// spock.lang.Specification を継承してテストクラスを作成
class DataConverterSpec extends Specification {

    // テストメソッドの定義
    def "正しく変換できる"() {
        given:
        // リテラル表記でListを作成してdefで変数へ代入
        def source = [1, 2, 3]
        def sut = new DataConverter(source)

        when:
        // Javaの関数インターフェースにはクロージャを渡すことができる
        sut.apply({ it * 10 })
        def data = sut.getData()

        then:
        // == による等値比較。Listの等値比較も簡単
        data == [10, 20, 30]
    }
}
```

# おわりに
Spockによるテスティングを始める上で必要なGroovyの基本知識をまとめました。  
実際に筆者がSpockを始めてからよく調べていたことを盛り込んだつもりですが、不足や誤り、わかりくい点などあればフィードバックを頂けると幸いです。