Spock验证Mock时触发MissingPropertyException问题求助
在Spock中验证Mock调用时使用动态生成的返回值
你遇到的问题是Spock的交互验证机制特性导致的——和Mockito不同,Spock的then块里的交互断言(比如1 * listener.onEvent(message))是在测试执行之前就被静态解析的,这时候when块里的局部变量message还未被定义,所以会抛出MissingPropertyException。
下面给你两种可行的解决方案:
方案1:提前声明变量扩大作用域
把message变量的声明移到测试方法的作用域顶部(比如given块中),这样Spock在解析then块时能识别到这个变量,执行时会使用它的实际值进行验证:
import spock.lang.Specification class MockingTest extends Specification { private MyListener listener = Mock() def 'test listener called'() { given: def message // 提前声明变量,扩大作用域 when: def service = new MyService(listener) 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); } } }
方案2:使用ArgumentCaptor捕获参数
如果你更习惯Mockito的参数捕获方式,Spock也支持ArgumentCaptor,通过捕获Mock调用时的参数来和返回值做对比:
import spock.lang.Specification import org.spockframework.mock.ArgumentCaptor class MockingTest extends Specification { private MyListener listener = Mock() def 'test listener called with argument captor'() { given: def messageCaptor = ArgumentCaptor.forClass(String) when: def service = new MyService(listener) def message = service.foo() then: // 捕获调用时传入的参数 1 * listener.onEvent(messageCaptor.capture()) // 验证捕获的参数和方法返回值一致 messageCaptor.value == 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); } } }
差异原因说明
Spock的交互验证采用声明式语法,会在测试启动前就解析所有交互断言以确保语法合规;而Mockito的验证是命令式的,只有执行到验证语句时才会处理变量。这就是为什么你在Mockito中可以直接使用局部变量,但Spock需要调整变量作用域或使用参数捕获器的核心原因。
内容的提问来源于stack exchange,提问作者GreenTea
相关产品推荐
相关产品推荐

