詳細
フィーチャ・メソッドのフロー
フィーチャ・メソッドは下記の4つのフローがあります
順序 | フロー内容 | 対応するブロック要素 |
---|---|---|
1 | Setup フィーチャのフィクスチャ設定 | setup |
2 | Stimulus 仕様対象システムの刺激を用意する | when,expect |
3 | Response システムに期待されるレスポンスを記述する | then,expect |
4 | Cleanup フィーチャの後始末をする | cleanup |
※ | −− | where |
Setup ブロック
setup: def stack = new Stack() def elem = "push me"
フィーチャの設定を行う為に一回だけ記述される。
省略可能。aliasとしてgivenを使用することも可能。
When/Then ブロック
when: // stimulus then: // response
when/thenは常にペアで使用される。
whenには任意のコードを記述可能。
thenには条件 conditions, 例外条件 exception conditions, インタラクション interactions と変数定義のみ記述可能。
フィーチャ・メソッドには複数のwhenーthenを記述可能
■条件
JUnitと異なり、条件はただの真偽値を表す式で記述します。
when: stack.push(elem) then: !stack.empty stack.size() == 1 stack.peek() == elem
■暗黙的条件と明示的条件 Implicit and explicit conditions
ブロックのトップレベルの条件は暗黙的条件として真偽値のみ指定すればよいが、
その他の場所で利用する場合は、明示的にassertを指定する必要があります。
def setup() { stack = new Stack() assert stack.empty }
■例外条件 Exception Conditions
例外条件はwhenブロックが例外を投げるべき時に使用されます。
thrownに予想される例外を記述します。
when: stack.pop() then: thrown(EmptyStackException) stack.empty
例外条件の後には他の条件などを続けて書くことが出来る為、例外の内容の指定をする場合などに有用です。
when: stack.pop() then: def e = thrown(EmptyStackException) e.cause == null
例外が起こらないことを確認することも出来ます
def "HashMap accepts null key"() { setup: def map = new HashMap() when: map.put(null, "elem") then: notThrown(NullPointerException) }
■インタラクション Interactions
複数のオブジェクトがどのように関わりあうかを表します
def "events are published to all subscribers"() { def subscriber1 = Mock(Subscriber) def subscriber2 = Mock(Subscriber) def publisher = new Publisher() publisher.add(subscriber1) publisher.add(subscriber2) when: publisher.fire("event") then: 1 * subscriber1.receive("event") 1 * subscriber2.receive("event") }
Expect ブロック
expectブロックは条件と変数定義のみを書いて、刺激と応答の両方を記述します。
expect: Math.max(1, 2) == 2
Cleanup ブロック
setup: def file = new File("/some/path") file.createNewFile() // ... cleanup: file.delete()
フィーチャのリソース開放のために一回だけ記述される。
Where ブロック
常にメソッドの最後に記述し、1回だけ記述できます。
def "computing the maximum of two numbers"() { expect: Math.max(a, b) == c where: a << [5, 3] b << [1, 9] c << [5, 9] }
ヘルパー・メソッド
何度も使用する条件の共通化などを行う際にヘルパー・メソッドとして処理を切り出すことができます。
ただし、Spockの親切で分かりやすいエラー出力を利用する場合は切り出したメソッドの中で
assertを行うようにコードを修正する必要があります。
以下、公式サイトのコード例
■修正前
def "offered PC matches preferred configuration"() { when: def pc = shop.buyPc() then: pc.vendor == "Sunny" pc.clockRate >= 2333 pc.ram >= 4096 pc.os == "Linux" }
■修正後1
def "offered PC matches preferred configuration"() { when: def pc = shop.buyPc() then: matchesPreferredConfiguration(pc) } def matchesPreferredConfiguration(pc) { pc.vendor == "Sunny" && pc.clockRate >= 2333 && pc.ram >= 4096 && pc.os == "Linux" }
この記述だとエラー出力が以下のようになり、分かりにくい
Condition not satisfied: matchesPreferredConfiguration(pc) | | false ...
■再修正後
ヘルパーメソッドを以下のようにすると分かりやすい出力になります
void matchesPreferredConfiguration(pc) { assert pc.vendor == "Sunny" assert pc.clockRate >= 2333 assert pc.ram >= 4096 assert pc.os == "Linux" }
以下、出力内容
Condition not satisfied: assert pc.clockRate >= 2333 | | | | 1666 false ...
■ドキュメントとしての仕様
各ブロックの後にテキスト記述を追加して仕様を分かりやすくすることができます。
setup: "open a database connection" // code goes here and: "seed the customer table" // code goes here and: "seed the product table" // code goes here