
spock 支持通过字符串拼接方式动态解析 mock 实例字段名并执行方法调用断言,从而实现“根据输入条件验证不同 handler 被调用”的参数化测试需求。
spock 支持通过字符串拼接方式动态解析 mock 实例字段名并执行方法调用断言,从而实现“根据输入条件验证不同 handler 被调用”的参数化测试需求。
在使用 Spock 编写单元测试时,常需验证被测代码是否按分支逻辑准确调用了特定依赖对象的方法。例如,当 Foo.handle(String) 根据输入 "A" 或 "B" 分别委托给 aHandler 或 bHandler 时,我们希望用同一组数据驱动测试,但断言目标需动态切换——这无法通过静态方法引用(如 ahandler.handle("A"))直接实现,因为 Spock 的交互断言(1 * ...)在 where 块中不支持表达式求值。
正确解法是利用 Groovy 的反射能力,在 then 块中通过 this."$handler" 动态访问当前测试实例的字段,并结合通配符 _ 进行宽松参数匹配:
def ahandler = Mock(AHandler)
def bhandler = Mock(BHandler)
def service = new Foo(ahandler, bhandler)
when:
service.handle(input)
then:
1 * this."$handler".handle(_) // 动态解析字段名,调用其 handle 方法(任意参数)
0 * _ // 确保无其他任何方法调用
where:
input | handler
"A" | "ahandler"
"B" | "bhandler"
⚠️ 注意事项:
- 字段名必须与
Mock变量名严格一致(如"ahandler",而非"aHandler"或"AHandler"),否则this."$handler"将抛出MissingPropertyException; -
handle(_)使用下划线表示“接受任意参数”,若需校验具体参数值,可替换为handle("A")等具名匹配; -
0 * _是全局调用抑制断言,确保没有意外的副作用调用,增强测试健壮性; - 此技巧仅适用于当前测试类(
this)中定义的 Mock 实例字段,不可用于局部变量或嵌套对象。
该方案简洁、可读性强,且完全符合 Spock 的数据驱动测试范式,是处理多分支委托逻辑验证的推荐实践。










