使用 Spock 测试应用参数约束

Applying argument constraints with Spock tests

我已经为一些 Java 类 编写了 Spock 测试。当我尝试验证参数中使用的确切对象时,测试失败了。

    def "all events are published to subscribers"() {
        given:
        EventSubscriber subscriber = Mock()
        when:
        subscriber.shouldRegister() >> true
        subscriber.interests() >> new HashSet<Intent>(Arrays.asList(COUNTER, GAUGE))
        publisher.subscribe(subscriber)
        def event = publisher.newEvent("test", COUNTER)
        event.start()
        def child = event.newChild("child", GAUGE)
        event.finish()
        then:
//        2 * subscriber.onCreate(event)
//        1 * subscriber.onStart(event, event.start)
//        1 * subscriber.onEnd(event, event.end)
//        1 * subscriber.onChild(event, child)
        2 * subscriber.onCreate(_)
        1 * subscriber.onStart(_, _)
        1 * subscriber.onEnd(_, _)
        1 * subscriber.onChild(_, _)
    }

注释掉的行失败

groovy.lang.MissingPropertyException: No such property: event for class: io.hypi.faf.api.EventPublisherTest

at io.hypi.faf.api.EventPublisherTest.all events are published to subscribers(EventPublisherTest.groovy:28)

http://spockframework.org/spock/docs/1.3/all_in_one.html#_argument_constraints 似乎暗示我可以传入一个值。第一个示例是一个字符串,但我认为类型无关紧要。

我做错了什么?

斯波克:1.3 Groovy:2.5 groovy-test-junit5-2.5.7 JDK: 11

交互测试中使用的对象实例应在 given 部分中定义。

这会起作用:

def 'all events are published to subscribers'() {
    given:
    EventSubscriber subscriber = Mock()
    subscriber.shouldRegister() >> true
    subscriber.interests() >> new HashSet<Intent>(Arrays.asList(COUNTER, GAUGE))
    publisher.subscribe(subscriber)
    def event = publisher.newEvent('test', COUNTER)
    def child = event.newChild('child', GAUGE)

    when:
    event.start()
    event.finish()

    then:
    2 * subscriber.onCreate(event)
    1 * subscriber.onStart(event, event.start)
    1 * subscriber.onEnd(event, event.end)
    1 * subscriber.onChild(event, child)
}

但是测试 onCreate()onChild() 的调用会出现问题,因为这些调用不在 when 部分,只有 onStart()onEnd() 可以匹配。

我没有你的 类 定义来查看详细信息,但我想 event.startevent.end 字段已在 start()finish() 中初始化方法然后 1 * onStart(event, event.start)1 * onEnd(event, event.end) 测试将不匹配,因为调用测试将在 event 具有不同的 startend 值的阶段完成。那么只有 1 * onStart(event, _)1 * onEnd(event, _) 测试才会匹配。


看看这个简单的例子,它与你的情况相似,但不同之处在于 event 实例是在 given 部分中准备的,而不是在 when 中修改的所以它将通过测试:

class InvocationWithArgumentsSpec extends Specification {
    void 'Invocation test works with arguments other then String'() {
        given:
        def subscriber = Mock(Subscriber)
        def simplePublisher = new Publisher()
        simplePublisher.subscribe(subscriber)
        def event = new SimpleEvent(name: 'test')

        when:
        simplePublisher.fireEvent(event)

        then:
        1 * subscriber.onEvent(event)
    }
}

interface Subscriber {
    void onEvent(SimpleEvent event)
}

class Publisher {
    Subscriber subscriber

    void subscribe(Subscriber subscriber) {
        this.subscriber = subscriber
    }

    void fireEvent(SimpleEvent event) {
        subscriber.onEvent(event)
    }
}

class SimpleEvent {
    String name
}

更新: 但是有一个解决方法适合您。它不是很好,但它可以工作并测试将正确的事件传递给订阅者方法(我猜 event 有类似 name 的东西):

def 'all events are published to subscribers'() {
    given:
    EventSubscriber subscriber = Mock()
    subscriber.shouldRegister() >> true
    subscriber.interests() >> new HashSet<Intent>(Arrays.asList(COUNTER, GAUGE))
    publisher.subscribe(subscriber)

    when:
    def event = publisher.newEvent('test', COUNTER)
    event.start()
    event.newChild('child', GAUGE)
    event.finish()

    then:
    1 * subscriber.onCreate({ it.name == 'test' })
    1 * subscriber.onCreate({ it.name == 'child' })
    1 * subscriber.onStart({ it.name == 'test' }, !null)
    1 * subscriber.onEnd({ it.name == 'test' }, !null)
    1 * subscriber.onChild({ it.name == 'test' }, { it.name == 'child' })
}