最近の単体テストでは欠かせないMockingですが、GroovyのテストフレームワークであるSpockでもなかなか強力なMocking機能が標準搭載されています。
この記事では、よくMockingのためのコードを記述するsetupSpecとsetupでの振る舞いについて、一個のテストクラスにまとめてみました。
MockTest.groovy
@Grab(group='org.spockframework', module='spock-core', version='0.7-groovy-2.0')
import spock.lang.*
class MockTest extends Specification {
interface ClassA{
int method1()
}
static ClassA classA_spec,s1
static ClassA classA_setup,a1
def setupSpec(){
classA_spec = Mock()
s1 = classA_spec
}
def setup(){
classA_setup = Mock()
a1 = classA_setup
}
def "setupSpecでMock()されたオブジェクトはメソッドの動作定義が出来ない(setup)"(){
setup:
classA_spec.method1() >> 1
expect:
s1.is(classA_spec) && s1.method1() != 1
}
def "setupSpecでMock()されたオブジェクトはメソッドの動作定義が出来ない(when)"(){
when:
classA_spec.method1() >> 2
then:
s1.is(classA_spec) && s1.method1() != 2
}
def "ただしsetupSpecでMock()されたオブジェクトでもwhereではメソッドが定義できる"(){
expect:
s1.is(classA_spec) && s1.method1() == 3
s.is(classA_spec) && s.method1() == 3
where:
s << [{classA_spec.method1() >> 3;s1}()]
}
def "setupでMock()されたオブジェクトはメソッドの動作定義ができる(setup)"(){
setup:
classA_setup.method1() >> 1
expect:
a1.is(classA_setup) && a1.method1() == 1
}
def "setupでMock()されたオブジェクトはメソッドの動作定義ができる(when)"(){
when:
classA_setup.method1() >> 1
then:
a1.is(classA_setup) && a1.method1() == 1
}
def "setupでMock()されたオブジェクトではwhereではメソッドが定義できない"(){
expect:"where時点のオブジェクトとも変わる"
a1.is(classA_setup) && a1.method1() != 1
!a.is(classA_setup) && a.method1() != 1
where:
a << [{classA_setup.method1() >> 1;classA_setup}()]
}
def "setupでMock()されたオブジェクトではdataテーブルが有効"(){
setup:
classA_setup.method1() >> data
expect:
a1.is(classA_setup) && a1.method1() == data
where:
data << [1,2,3]
}
def "setupSpecでMock()されたオブジェクトのメソッドは他のメソッドで定義済みだとそれ以降定義できない"(){
expect:
s1.is(classA_spec) && s1.method1() == 3
where:
data << [4,5,6].each {
classA_spec.method1() >> it
}
}
def "そもそも同一のMockオブジェクトのメソッドの動作を定義できるのは一度きり"(){
setup:
classA_setup.method1() >> data
classA_setup.method1() >> 1
expect:
a1.is(classA_setup) && a1.method1() == data
where:
data << [1,2,3]
}
}
これらの振る舞いから、
- テストを通じて振る舞いが変わらないMock対象
- setupSpecでMockオブジェクトを用意する
- 同様にsetupSpecで振る舞いまで定義する
ことによって、テスト全体の前提となるMock定義を一箇所で管理する
- それぞれのテストにおいて振る舞いを変える必要のあるMock対象
- setupでMockオブジェクトを用意する
- 各テストメソッドのsetupまたはwhenで動作を定義する
ことによって、whereによるDataDrivenなテストをやりやすくする
と良いでしょうということが考えられます。