パーソナルツール
現在の場所: ホーム Users YAMADA Masaki 2009 0912 SpockInJapanese Interactions
ログイン


パスワードを忘れた?
 

Interactions

— カテゴリー:

Groovy/Grailsの振る舞い駆動開発 (Behavior-driven Development, BDD) フレームワーク Spockの使い方 (邦訳)

インタラクション Interactions     

オブジェクト間のインタラクションを表す方法を学ぼう.

モックを作る

モックは, インタフェース, finalでないJavaクラス, finalでないGroovyクラス (これは実験段階) に対して作ることができます. 今のところ, すべてのモックは「てーげー」(lenient) です. つまり, もしあるメソッド呼び出しがインタラクションと対応しない場合, そのメソッドの戻り値の型のデフォルト値を返すようになっています.

def subscriber = Mock(Subscriber) // "動的な" スタイル (モックの名前を変数名から推測)

Subscriber subscriber = Mock()    // "静的な" スタイル (モックの名前と型を変数名とその型から推測)

大域的なインタラクションと局所的なインタラクション

then ブロックの外側で定義されるインタラクションを 大域的 global と呼びます. このようなインタラクションは, その定義の時点からフィーチャ・メソッドの最後まで有効です.

setup:
subscriber.isAlive() >> true

then ブロックの内部で定義されるインタラクションを 局所的 local と呼びます. このようなインタラクションは, それに先立つ when ブロックの内部でのみ有効です.

when: publisher.send(event)
then: 1 * subscriber.receive(event)

任意インタラクションと必須インタラクション

任意 (optional) インタラクションは, 基数を持ちません. 戻り値がなければなりません.

then: subscriber.isAlive() >> true

必須インタラクションは基数を持たなければなりません. 戻り値はあってもなくても構いません.

then: 1 * subscriber.isAlive() >> true

then: n * subscriber.receive(event)

いちばん普通に使われる組み合わせは大域的+任意 (setupの一部としてのスタブ) と局所的+必須 (when-blockの一部としてのモック) ですが, 他の二つの組み合わせも可能です.

基数 Cardinalities

n * subscriber.receive(event)      // ちょうどn回

(n.._) * subscriber.receive(event) // 少なくともn回

(_..n) * subscriber.receive(event) // 多くともn回

ターゲットの制約

_.receive(event) // receive は任意のモック・オブジェクトに対して呼び出される

メソッドの制約

subscriber./set.*/(_) //  subscriberのすべてのsetterが呼び出される (任意の正規表現を書ける)

引数の制約

subscriber.receive(_)                      // 任意の引数

subscriber.receive(!null)                  // nullでない任意の引数

subscriber.receive(event)                  // eventに等しい任意の引数

subscriber.receive(!event)                 // eventに等しくない任意の引数

subscriber.receive(_ as Message)           // Messageとis-aであるような任意の引数 (nullはだめ)

subscriber.receive( { it.priority >= 5 } ) // 自前の制約

戻り値

subscriber.isAlive() >> true                     // 単独の戻り値, 無限に繰り返し

subscriber.isAlive() >>> [true, false, true]     // 複数の戻り値 (Groovyで繰り返しを表すようなものなら何でも可), 最後の一つを無限に繰り返し

def random = new Random()
subscriber.isAlive() >> { random.nextBoolean() } // 自前の戻り値

subscriber.isAlive() >> { throw new TimeoutException() } // 自前のアクション

厳密なインタラクション定義

もしすべてのモックが「てーげー」だとすると, 明示的に指定した以外のインタラクションが起こらないと言うことをどうやって表したらいいのでしょう?

/* あり得べきインタラクションをここに書く */
0 * _._ // それ以外のモックへのメソッド呼び出しはない

インタラクションの明示的記法

もし then ブロックにあるインタラクション定義が, 同じブロック内にある他のコードに依存していたら, この関係も次のように明示しなければなりません:

then:
interaction {
  def count = 3
  count * suscriber.receive(_)
}

ヘルパー・メソッドでも同様:

then:
interaction {
  subscriberReceivesThreeMessages()
}

...

def subscriberReceivesThreeMessages() {
  3 * subscriber.receive(_)
  // それ以外のインタラクションがあればここに書く
}

original: http://code.google.com/p/spock/wiki/Interactions

translated into Japanese by masaki@metabolics.co.jp at 2009.12.06