Spock入門 
G* ワークショップ Z 札幌 2014 
2014/09/27
お前誰よ 
• 名前:杉浦孝博 
• twitter : @touchez_du_bois 
• 昼のお仕事: 
Grailsアプリ、C#アプリ、VB.NETアプリの保守 
とあるサイトの運用、保守 
時々開発
Today’s 
Goal. 
(本日の目標)
本日の目標 
• Spockってどんなもんか、 
「なんとなく」わかった気になる。 
• Spockを使ってみたくなる。
Today’s 
Contents 
(本日の内容)
本日の内容 
• 入門編 
• Spockとは 
• Spockの利点 
• 構造 
• Power Assert 
• データ駆動テスト 
• 相互作用中心のテスト
本日の内容 
• その他 
• Spockの拡張機能 
• Spockのモジュール 
• Spockと一緒に 
• まとめ
Introduction 
(入門)
What’s 
Spock? 
(Spockとは)
Spockとは 
• Java, Groovy向けの、テスト・仕様 
フレームワーク。 
• たいていのIDE、ビルドツール、CI 
サーバで使用可能。
Spockのバージョン 
• 安定バージョンは0.7。 
• スナップショットで1.0がある。 
• groovy 1.xと2.x用がある。
使い所 
• JavaやGroovyで作成したクラスの 
テストに。 
• TDD(Test Driven Development)のフ 
レームワークとして。 
• BDD(Behavior Driven Development) 
のフレームワークとして。
Advantages 
of Spock 
(Spockの利点)
Structure 
(構造)
構造 
• クラス内の構造が決まっている。 
• 役割ごとにメソッドが分かれている。 
• メソッドの中も役割ごとに分かれてい 
る。 
⇒ 読みやすい構造、書きやすい構造。
Spockの構成要素 
• Specification 
• Fields 
• Fixture Methods 
• Feature Methods 
• Blocks 
• Helper Methods
Specification 
• 対象クラスのテスト内容・仕様を記述。 
• spock.lang.Specificationクラスを継 
承。 
import spock.lang.* 
! 
class TargetClassSpec extends Specification { 
// Fields 
// Fixture Methods 
// Feature Methods 
// Helper Methods 
}
Fields 
• テストで使用するオブジェクトを宣言。 
• Featureメソッド実行ごとに初期化され 
るため、基本的に、インスタンス変数は 
Featureメソッド間で共有できない。 
• 共有したい場合、@Sharedを付ける。 
@Shared 
def stack = new Stack()
Fixture Methods 
• テストの準備(setup)、後始末(cleanup) 
を行う。 
def setup() {} // 各Featureメソッドの実行前に実行 
def cleanup() {} // 各Featureメソッドの実行後に実行 
def setupSpec() {} // 最初のFeatureメソッドの実行前に実行 
def cleanupSpec() {} // 最後のFeatureメソッドの実行後に実行
Feature Methods 
• テストの内容、仕様の内容を記述。 
• 4つのフェーズからなり、それぞれBlock 
を記述。 
• Setup(前処理、前提条件) 
• Stimulus(実行) 
• Response(検証) 
• Cleanup(後処理)
Block 
• フェーズに応じた、テスト、仕様のコー 
ドを記述。 
• setup: / given: 
• when: 
• then: 
• expect: 
• cleanup: 
• and: 
• where:
BlockとPhase 
Block Phase 
setup: / given: Setup 
when: Stimulus 
then: Response 
expect: Stimulus + Response 
cleanup: cleanup 
where: - 
and: -
when~thenの例 
def "push後のサイズは1"() { 
setup: 
def stack = new Stack<Integer>() 
when: 
stack.push(5) 
then: 
stack.size() == 1 
}
expectの例 
def "10と20で大きいのは20"() { 
expect: 
Math.max(10, 20) == 20 
}
Helper Methods 
• Featureメソッドが大きくなった場合 
に、意味がある内容をメソッド化する。 
• setupやcleanupも処理が大きくなった 
場合に、メソッド化する。
Advantages 
of Spock 
(Spockの利点)
Power 
Assert 
(ぱわーあさーと)
Power Assert 
• テスト・仕様の内容を満たさない場合、 
各部分式の値を表示する。 
• SpockからGroovy本体に取り込まれ 
た。 
⇒ どこが違うか、どこから違うか、 
  ということが、比較的わかりやすい。
Power Assert 
def "maximum of two numbers"() { 
setup: 
def a = 2 
def b = 1 
def c = 1 
expect: 
Math.max(a, b) == c 
}
Power Assert 
Math.max(a, b) == c 
| | | | | 
2 2 1 | 1 
false
Power Assert 
@Unroll 
def "str1 == str2"() { 
setup: 
def str1 = "abcdefghijklmnopqrstuvwxyz" 
def str2 = "abcdefghijk1mnopqrstuvwxyz" 
expect: 
str1 == str2 
}
Power Assert 
str1 == str2 
| | | 
| | abcdefghijk1mnopqrstuvwxyz 
| false 
| 1 difference (96% similarity) 
| abcdefghijk(l)mnopqrstuvwxyz 
| abcdefghijk(1)mnopqrstuvwxyz 
abcdefghijklmnopqrstuvwxyz
Advantages 
of Spock 
(Spockの利点)
Data Driven 
Testing 
(データ駆動テスト)
データ駆動テスト 
• 入力値と期待する結果の組み合わせを検 
証するために、同じテスト・仕様のコー 
ドを複数回実行したい場合に効果的。 
• コードとデータを分離。 
• コードを安易に複製しないで済む。 
• データを自動生成したり、外部リソース 
から読み込んだりできる。
よくある例 
• 入力値と期待値が異なるがコードは同じ。 
def "maximum of two numbers"() { 
expect: 
Math.max(1, 3) == 3 
Math.max(7, 4) == 4 
Math.max(0, 0) == 0 
}
データテーブル 
• コードとデータを分離。 
def "maximum of two numbers"() { 
expect: 
Math.max(a, b) == c 
where: 
a | b | c // データ変数 
1 | 3 | 3 // データ行 
7 | 4 | 7 // 〃 
0 | 0 | 0 // 〃 
} 
// Math.max(1, 3) == 3 
// Math.max(7, 4) == 7 
// Math.max(0, 0) == 0 
// の3イテレーション実施。
データテーブル 
• 入力値と期待値を(多少)わかりやすく。 
def "maximum of two numbers"() { 
expect: 
Math.max(a, b) == c 
where: 
a | b || c // データ変数 
1 | 3 || 3 // データ行 
7 | 4 || 7 // 〃 
0 | 0 || 0 // 〃 
}
どこが失敗? 
• 何回目のイテレーションで失敗したか 
わからない。 
def "maximum of two numbers"() { 
expect: 
Math.max(a, b) == c 
where: 
a | b || c 
1 | 3 || 3 
7 | 4 || 4 
0 | 0 || 0 
} 
maximum of two numbers FAILED 
! 
Condition not satisfied: 
! 
Math.max(a, b) == c 
| | | | | 
7 7 4 | 4 
false
@Unroll 
• @Unrollを付けたメソッドまたはクラス 
は、イテレーション毎にレポートされる。 
@Unroll 
def "maximum of two numbers"() { 
expect: 
Math.max(a, b) == c 
where: 
a | b || c 
1 | 3 || 3 
7 | 4 || 4 
0 | 0 || 0 
} 
maximum of two numbers[0] PASSED 
maximum of two numbers[1] FAILED 
! 
Math.max(a, b) == c 
| | | | | 
7 7 4 | 4 
false 
! 
maximum of two numbers[2] FAILED
もう少しわかりやすく 
• メソッド名にプレースホルダを使うこと 
で、レポート結果がわかりやすく。 
@Unroll 
def "maximum of #a and #b is #c"() { 
expect: 
Math.max(a, b) == c 
where: 
a | b || c 
1 | 3 || 3 
7 | 4 || 4 
0 | 0 || 0 
} 
maximum of 1 and 3 is 3 PASSED 
maximum of 7 and 4 is 4 FAILED 
! 
Math.max(a, b) == c 
| | | | | 
7 7 4 | 4 
false 
! 
maximum of 0 and 0 is 0 FAILED
データパイプ 
• データ変数ごとにデータプロバイダを用 
意し、<<演算子で接続する。 
def "maximum of two numbers"() { 
expect: 
Math.max(a, b) == c 
where: 
a << [ 1, 7, 0 ] 
b << [ 3, 4, 0 ] 
c << [ 3, 7, 0 ] 
} 
// Collectionだけでなく、テキストファイルやデータベースなど、 
// 外部リソースから取得することも可能。
データパイプで複数の値 
• データプロバイダが複数の値を返す場合、 
複数のデータ変数に同時に接続可能。 
@Shared sql = Sql.newInstance("jdbc:h2:mem:", "org.h2.Driver") 
! 
def "maximum of two numbers"() { 
expect: 
Math.max(a, b) == c 
where: 
[a, b, c] << sql.rows("select a, b, c from maxdata") 
}
データ変数へ代入 
• データ変数に直接値を代入することも可 
能。 
def "maximum of two numbers"() { 
expect: 
Math.max(a, b) == c 
where: 
a = 3 
b = Math.random() * 100 
c = a > b ? a : b 
}
Advantages 
of Spock 
(Spockの利点)
Interaction 
Based Testing 
(相互作用中心のテスト)
相互作用中心のテスト 
• Publish - Subscribeのように、 
オブジェクト同士の振る舞いをテスト・ 
仕様化したい場合。 
• 相互作用相手について、 
本物のオブジェクトを使うこともあるが、 
モックオブジェクトを使うこともある。
モックフレームワークの提供 
• 簡単に相互作用中心のテストを書けるよ 
うに、Spock独自のモックフレームワー 
クを提供。 
• JMock, EasyMock, Mockitoといった既 
存のモックフレームワークと一緒に使う 
ことも可能。
Spockでは 
• Spockでは、次の3つの方法を用意。 
• モック(Mock) 
• スタブ(Stub) 
• スパイ(Spy)
プログラム例 
class Publisher { 
List<Subscriber> subscribers = [] 
void send(String message) { 
subscribers.each { 
it.receive(message) 
} 
} 
void send(Event event) { 
subscribers.each { 
it.receive(event) 
} 
} 
} 
! 
interface Subscriber { 
void receive(String message) 
void receive(Event event) 
}
モックオブジェクトの作成 
• Mockメソッドで作成 
// モックオブジェクトのインタフェース(クラス)を指定して作成 
def subscriber = Mock(Subscriber) 
! 
// 変数の型からモックオブジェクトのインタフェース(クラス)の 
// 型を推論 
Subscriber subscriber = Mock()
モックオブジェクトの準備 
• 例えば、こんな感じで。 
class PublisherSpec extends Specification { 
Publisher publisher = new Publisher() 
Subscriber subscriber1 = Mock() 
Subscriber subscriber2 = Mock() 
! 
def setup() { 
publisher.subscribers << subscriber1 
publisher.subscribers << subscriber2 
} 
}
モッキング 
• テスト/仕様対象のオブジェクトと、相互 
作用するオブジェクトの間の、インタラ 
クション(相互作用)を宣言すること。 
def "should send messages to all subscribers"() { 
when: 
publisher.send("hello") 
! 
then: 
1 * subscriber1.receive("hello") 
1 * subscriber2.receive("hello") 
}
インタラクション 
• 多重度(cardinality)、対象制約(target 
constraint)、メソッド制約(method 
constraint)、引数制約(argument 
constraint)からなる。 
1 * subscriber.receive("hello") 
| | | | 
| | | argument constraint 
| | method constraint 
| target constraint 
cardinality
多重度 
• 何回メソッド呼び出しが行われるかを指 
定する。 
• 固定の数値や範囲を指定可能。 
1 * subscriber.receive("hello") // 1回 
0 * subscriber.receive("hello") // 0回 
(1..3) * subscriber.receive("hello") // 1〜~3回 
(1.._) * subscriber.receive("hello") // 1回以上 
(_..3) * subscriber.receive("hello") // 3回以下 
_ * subscriber.receive("hello") // 0回以上
対象制約 
• どのオブジェクト(モックオブジェクト) 
を対象にするかを指定する。 
1 * subscriber1.receive("hello") // subscriber1に対して 
1 * _.receive("hello") // 任意のモックオブジェクト
メソッド制約 
• どのメソッド呼び出しを対象にするかを 
指定する。 
1 * subscriber.receive("hello") // receiveメソッド 
1 * subscriber._("hello") // 任意のメソッド 
1 * subscriber./r.*e/("hello") // rで始まりeで終わるメソッド
引数制約 
• どんな引数を期待するかを指定する。 
// 引数が"hello"という文字列 
1 * subscriber.receive("hello") 
// 引数が"hello"という文字列ではない 
1 * subscriber.receive(!"hello") 
// 引数なし 
1 * subscriber.receive() 
// 1引数(nullも含む) 
1 * subscriber.receive(_) 
// 任意の引数 
1 * subscriber.receive(*_) 
// nullではない 
1 * subscriber.receive(!null) 
// String型の引数(nullは含まれない) 
1 * subscriber.receive(_ as String) 
// 指定された条件を満たす引数 
1 * subscriber.receive({ it.size() > 3 })
スタビング 
• 特定のメソッド呼び出しに対する応答を 
宣言すること。 
• 何回呼ばれても、特定の値を返したり、 
何らかの副作用が働くようにする。
スタビング 
• モッキングに比べ、多重度の指定がない 
代わりに、レスポンスジェネレータ 
(Response Generator)を指定する。 
subscriber1.receive(_) >> "ok" 
| | | | 
| | | response generator 
| | argument constraint 
| method constraint 
target constraint
スタビングの例 
interface Subscriber { 
def setup() { 
publisher.subscribers << subscriber1 
publisher.subscribers << subscriber2 
! 
// receiveメソッドの戻り値は常に"ok"とする 
subscriber1.receive(_) >> "ok" 
subscriber2.receive(_) >> "ok" 
} 
// String型の値を返すように変更 
String receive(String message) 
String receive(Event message) 
}
一連の値を返す 
• >>>演算子の後に、リストなどイテレー 
ティブな値を指定する。 
// 1回目: "ok" 
// 2回目: "error" 
// 3回目: "error" 
// 4回目以降: "ok" 
subscriber1.receive(_) >>> ["ok", "error", "error", "ok"]
動的に値を返す 
• >>演算子の後に、動的な値を返すクロー 
ジャを指定する。 
subscriber1.receive(_) >> { String message -> 
message.size() > 3 ? "ok" : "fail" 
}
副作用の実行 
• >>演算子の後のクロージャ中に、副作用 
としての処理を記述する。 
subscriber1.receive(_) >> { String message -> 
println message 
throw new InvalidArgumentException() 
}
組み合わせ 
• モッキングとスタビングを組み合わせて 
使うことも可能。 
1 * subscriber1.receive("message1") >> "ok" 
1 * subscriber2.receive("message2") >> "fail"
スタブオブジェクトの作成 
• Stubメソッドで作成する。 
• Mockメソッドで作成した場合、モッキ 
ングもスタビングもできるが、Stubメ 
ソッドで作成した場合はスタビングのみ。 
// スタブオブジェクトのインタフェース(クラス)を指定して作成 
def subscriber = Stub(Subscriber) 
! 
// 変数の型からスタブオブジェクトのインタフェース(クラス)の 
// 型を推論 
Subscriber subscriber = Stub()
スパイ 
• 本物のオブジェクトを監視して、モッキ 
ングやスタビングを行う。 
• メソッド呼び出しは、本物のメソッド呼 
び出しに移譲され、その際の戻り値がス 
パイを経由して返される。
スパイオブジェクトの作成 
• Spyメソッドで作成 
// スパイ対象のクラスを指定して作成 
def subscriber = 
Spy(SubscriberImpl, constructorArgs: ["Fred"])
スパイでのスタビング 
• スパイで普通にスタビングを行うと、本 
物のメソッドが呼ばれなくなる。 
// スパイ対象のクラスを指定して作成 
def subscriber = 
Spy(SubscriberImpl, constructorArgs: ["Fred"]) 
! 
// スタビング。本物のreceiveメソッドは呼ばれない。 
subscriber.receive(_) >> "ok"
スタビング+本物のメソッド 
• callRealMethodメソッド、あるいは 
callRealMethodWithArgsメソッドを使 
うことで、任意のコードの実行と、本物 
のメソッドへの委譲が行われる。 
// 本物のreceiveメソッドが呼ばれた後、 
// 戻り値を動的に変更 
subscriber.receive(_) >> { String message -> 
callRealMethod() 
message.size() > 3 ? "ok" : "fail" 
}
スタビング+本物のメソッド 
• callRealMethodメソッドと 
callRealMethodWithArgsメソッドの違 
いは、後者は呼び出し時の引数を差し替 
えたい場合に使用する。 
// 本物のreceiveメソッドを、違う引数で実行し、 
// 戻り値を動的に変更 
subscriber.receive(_) >> { String message -> 
callRealMethodWithArgs("Changed message") 
message.size() > 3 ? "ok" : "fail" 
}
et cetera 
(その他)
Spock 
Extensions 
(Spock拡張機能)
Spockの拡張機能 
• Spockの動作を拡張したり変更した 
りすることができる。 
• 仕組みとして、ビルトイン機能拡張 
と、カスタム機能拡張がある。
ビルトイン拡張機能 
• ビルトイン拡張機能のほとんどは、 
アノテーションを通して使用する。 
• @Unrollもその一例。 
• 他にも、@Ignor, @IgnorRest, 
@IgnorIf, @Requiresなどがある。 
• 自作も可能。
カスタム拡張機能 
※詳細不明のため省略
Spock 
Modules 
(Spockモジュール)
Spockのモジュール 
• Spockの動作を拡張したり変更した 
りすることができる。 
• githubで、SpockのCore以外にもい 
くつかモジュールを提供している。
純正なもの 
• spock-unitils 
• Unitilsというテスト用ユーティリ 
ティをSpockと統合したもの。 
• spock-spring, spock-boot 
• それぞれ、Spring TestContext 
やSpring Bootと統合したもの。
純正でないもの 
• Spock Report Extension 
• 実行結果のレポートを作成するた 
めのグローバル拡張機能。 
• https://github.com/ 
renatoathaydes/spock-reports
With Spock 
(Spockと一緒に)
Spockと組み合わせる 
• テスティングフレームワークの中に 
は、Spockをサポートしていたり、 
Spockと組み合わせて使ったりする 
ものがある。
Geb + Spock 
• Gebとは、Webブラウザを使うWeb 
アプリケーションの操作を自動化・ 
自動実行するためのソフトウェア。 
• Geb用のSpecificationクラスを提供。
Arquillian + Spock 
• Arquillianとは、自動テストでJavaEE 
コンテナを利用可能にするためのソ 
フトウェア。 
• ArquillianをSpockと組み合わせて使 
えるように、アノテーションなど機 
能拡張を提供。
Robospock 
• Robospockとは、Spockを使って 
Androidアプリケーションをテストする 
ためのソフトウェア。 
• Android用のユニットテストフレームワー 
クであるRobolectricとSpockを組み合 
わせ、Specificationクラスを提供。
To wrap up 
(まとめ)
まとめ 
• Spockは、テスト・仕様が書きやす 
く読みやすいフレームワークです。 
• JUnitの代わりにユニットテストで使 
う等、導入しやすい所から初めてみ 
るのはいかがでしょうか。 
!
参考URL 
• 本家 
• https://code.google.com/p/spock/ 
• ソースコード 
• https://github.com/spockframework/spock 
• リファレンスドキュメント(英語版) 
• http://spock-framework.readthedocs.org/en/latest/ 
• リファレンスドキュメント(日本語版) 
• http://spock-framework-reference-documentation-ja.readthedocs.org/ja/latest/ 
• G*ワークショップZ May 2013 - Spockハンズオンの資料 
• https://github.com/spockframework/spock
参考URL 
• Geb 
• http://www.gebish.org/ 
• Arquillian 
• http://arquillian.org/ 
• Arquillian TestRunner Spock 
• http://arquillian.org/modules/spock-test-runner/ 
• RoboSpock 
• http://robospock.org/
ご清聴 
ありがとう 
ございました

Introduction to Spock