在 Spock 模拟中无法根据结果验证模拟:MissingPropertyException:没有这样的 属性

In Spock mocks impossible to verify mock against result: MissingPropertyException: No such property

我在尝试检查 then 块中的 mock 时遇到了一些奇怪的错误,其中包含测试方法返回的结果,我事先并不知道。这是一个简单的例子:

import spock.lang.Specification

class MockingTest extends Specification {

    private MyListener listener = Mock()

    def 'test listener called'() {
        when:
        def service = new MyService(listener)
        def message = service.foo()
        then:
        1 * listener.onEvent(message)
    }

    class MyService {
        private MyListener listener;

        MyService(MyListener listener) {
            this.listener = listener
        }

        String foo() {
            String message = "Hello " + new Random().nextInt(10);
            listener.onEvent(message)
            return message;
        }
    }

    class MyListener {
        void onEvent(String message) {
            System.out.println(message);
        }
    }
}

错误是:

No such property: message for class: MockingTest
groovy.lang.MissingPropertyException: No such property: message for class: MockingTest
    at MockingTest.test listener called(MockingTest.groovy:14)

事件

1 * listener.onEvent(message)

放在 then 块中似乎 Spock 试图尽早初始化它,甚至在 when 块执行之前。

有什么方法可以解决这个问题,并检查 mock 是用某个局部变量而不是常量调用的吗? 用 java + mockito 做的事情很简单,用 Spock 看起来很复杂:(

您可以为此目的使用捕获技术,您可以在其中捕获 onEvent 方法调用的第一个参数 (it[0]) 并将其分配给预先声明的变量 (capturedMessage ):

def 'test listener called'() {
    given:
    def service = new MyService(listener)
    String capturedMessage = null
    when:
    def message = service.foo()
    then:
    1 * listener.onEvent(_) >> { capturedMessage = it[0] as String }
    message == capturedMessage
}

您的示例中的问题是交互测试 (1 * listener.onEvent(message)) 在 foo() 调用完成之前执行,然后尚未声明 [​​=16=] 变量。

旁注:given 是用于声明和初始化测试数据的右侧部分,如 service