如何在spock / groovy中窥探关闭或代理?

时间:2017-09-01 12:19:45

标签: groovy spock

如何在spock / groovy中窥探关闭或代理?

Spock有一个限制,您无法使用以下样式interaction testing模式:

setup:
subscriber.receive("message1") >> "ok"

when:
publisher.send("message1")

then:
1 * subscriber.receive("message1")

因为1 *交互行会覆盖" ok"的存根返回。你必须把它们放在同一条线上:

1 * subscriber.receive("message1") >> "ok"

大多数情况下这是可以的,但是对于某些需要存在更复杂行为的情况,能够将存根行为和交互分开是非常好的。

我嘲笑/存根的所有内容都可以用Closure表示,但我无法SpyClosure工作(或SpyProxyClosure)。所以我有以下Closure-lite类:

#!groovy
import spock.lang.Specification

class C {
    def c
    C (Closure c) { this.c = c }

    def call (Map args = null) { args? c?.call (args) : c?.call() }
    def call (Map args = null, one) { args? c?.call (args, one) : c?.call (one) }
    def call (Map args = null, one, two) { args? c?.call (args, one, two) : c?.call (one, two) }
    // etc.
}

尽管它们分离了存根行为和交互,但仍允许以下测试通过:

class spyTest extends Specification {

    void "should accept 0 args" () {
        given:
            def foo = Spy (C, constructorArgs:[{return "foo"}])
        when:
            def result = foo ()
        then:
            1 * foo()
            result == "foo"
    }

    void "should accept 1 positional args, 0 named args" () {
        given:
            def foo = Spy (C, constructorArgs:[{ one -> ["foo", one]}])
        when:
            def result = foo (1)
        then:
            1 * foo(1)
            result == ["foo", 1]
    }

    void "should accept 1 args, + 1 named args" () {
        given:
            def foo = Spy (C , constructorArgs:[{ args, one -> return ["foo", args, one]}])
        when:
            def result = foo (1, a:'a')
        then:
            1 * foo(1, a:'a')
            result == ["foo", [a:'a'], 1]
    }

    void "should accept 2 args, + 0 named args" () {
        given:
            def foo = Spy (C , constructorArgs:[{ one, two -> return ["foo", one, two]}])
        when:
            def result = foo (1,2)
        then:
            1 * foo(1,2)
            result == ["foo", 1, 2]
    }

    void "should accept 2 args, + 2 named args" () {
        given:
            def foo = Spy (C , constructorArgs:[{ args, one, two -> return ["foo", args, one, two]}])
        when:
            def result = foo (1,2, a:'a', b:'b')
        then:
            1 * foo(1,2,a:'a', b:'b')
            result == ["foo", [a:'a', b:'b'], 1, 2]
    }

}

这是可行的,如果有点笨重,但显然它更好更有活力"关闭"比我必须添加每个潜在数量的参数的类。

因此可能有更动态的解决方案(如何?),或者使用SpyGroovySpy的事实是否禁止更加动态的间谍课?

1 个答案:

答案 0 :(得分:0)

你能否详细说明一下,你所展示的一切都可以通过模拟轻松完成,而不需要间谍。


class MockTest extends Specification {

  void "should accept 0 args" () {
    given:
    def foo = Mock (C)
    when:
    def result = foo ()
    then:
    1 * foo() >> 'foo'
    result == "foo"
  }

  void "should accept 1 positional args, 0 named args" () {
    given:
    def foo = Mock (C)
    when:
    def result = foo (1)
    then:
    1 * foo(1) >> { args -> ["foo", args[0]]}
    result == ["foo", 1]
  }

  void "should accept 1 args, + 1 named args" () {
    given:
    def foo = Mock (C)
    when:
    def result = foo (1, a:'a')
    then:
    1 * foo(1, a:'a') >> { args, one -> ["foo", args, one]}
    result == ["foo", [a:'a'], 1]
  }

  void "should accept 2 args, + 0 named args" () {
    given:
    def foo =  Mock (C)
    when:
    def result = foo (1,2)
    then:
    1 * foo(1,2) >> { one, two -> ["foo", one, two]}
    result == ["foo", 1, 2]
  }

  void "should accept 2 args, + 2 named args" () {
    given:
    def foo = Mock (C)
    when:
    def result = foo (1,2, a:'a', b:'b')
    then:
    1 * foo(1,2,a:'a', b:'b') >> { args, one, two -> ["foo", args, one, two]}
    result == ["foo", [a:'a', b:'b'], 1, 2]
  }

}