LoginSignup
8
8

More than 5 years have passed since last update.

Spockにおいて、setupSpecでMockした場合とsetupでMockした場合の振る舞いまとめ

Posted at

最近の単体テストでは欠かせない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なテストをやりやすくする

と良いでしょうということが考えられます。

8
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
8