インタラクションが効かない

example

groovy void testTargetMethod() { Hoge hoge = this.getHoge() hoge.doSomething() } private Hoge getHoge() { return new Hoge() }
def "test testTargetMethod"() { setup: Hoge hogeMock = Mock() TestTargetSpy spy = GroovySpy() 1 * spy.getHoge() >> hogeMock when: def result = spy.testTargetMethod() then: result == hogeMock }

症状

  • spy.getHoge() が呼び出されない (0 invocation)

対策

  • Spy() ではなく GroovySpy() を利用する
  • GroovySpy(global: true) にしてみる
  • テスト対象クラスの getHoge() を protected メソッドにしてみる

Mock オブジェクトは boolean に変換されると false になる

example

Hoge hogeMock = GroovyMock()
if (hogeMock) { }

症状

Mock/GroovyMock は boolean にすると false になってしまうため、if の中に通らない

対策

条件がfalseにならないようにする
Groovy truth を使わず、より厳格に null チェックを行う

if (hogeMock != null) { }

メモ

- registerMetaClass() (Grails 2.3まで) - 以下利用時に必須 - Hoge.metaClass.'static'.hogehoge = {} - Groovy***(Hoge, global: true) - 忘れると、JVMが終了するまで振る舞いが変わるので、他のテストに影響出るよー - Grails 2.3からは、@ConfinedMetaClassChanges() を使う - Mock()とGroovyMock()の違い - Groovyで実行時に追加されるメソッド(find, eachとか)は、GroovyMock()じゃないと振る舞いを指定できない - setProperty("hoge", hoge), setHoge(hoge)で引っかかるものが異なる - Mock()を使う場合、かつそのオブジェクトが他のクラスを継承していた場合に、そのクラス(親クラス)に定義されたメソッドの振る舞いを設定できない - GroovySpy(global: true) - privateメソッドの呼び出しもpartial mock化できる - registerMetaClassをお忘れなく - ControllerSpecでは使用不可能, protectedメソッドにしてGroovySpy()を使う - Inner classのテスト記述注意 - 第一引数に、Inner classが定義されているインスタンスを入れる必要がある - これは、Javaの仕様 - setupで定義した変数をwhen/thenから参照できない場合がある? - 発生条件を詳細に調査していないが、引っかかることがある - whereではメソッド内で定義した変数を参照できない - new/newInstance()などの振る舞いの定義方法 - 全クラス共通になるので、複数クラスのnewに一度に振る舞いを設定する場合は要注意 - DateのMock - 2つ以上作って、==で比較してもtrueになってしまう - equals()はfalseになる謎仕様 - Spock以外のTips - http-builder - BuildConfigに記載する際に注意する - http://jira.grails.org/browse/GRAILS-9990?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel - Grailsスクリプト中に「//」のコメントは書けないっぽい - http://cave-of-twilight.blogspot.jp/2010/04/ry.html