Spock 模拟验证 returns 0 次调用
Spock mock verify returns 0 invocations
我正在开发一个 Spring 引导 java 服务,其中包含一个 Camel 处理器 class,如下所示:
public class MyProc implements Processor {
@Autowired
private LogService logService;
public void process(Exchange e) {
// exchange object processing
logService.update(e)
}
}
我有以下 Spock 测试:
class MyProcTest extends Specification {
@Shared def logService = Mock(LogService)
@Shared def proc = new MyProc()
def ctx = new DefaultCamelContext()
def exch = new DefaultExchange(ctx)
void setupSpec() {
proc.logService = logService
}
def "log is updated when valid exchange is processed"() {
given:
exch.getIn().setBody(//xml string set on body)
when:
proc.process(exch)
then:
1 * logService.update(_)
}
}
当我 运行 这样做时,我遇到了一个失败,说明 1 * logService.update(_) 的调用太少(0 次调用)。我尝试调试代码,在 MyProc 中,语句被命中,并且 logService 对象在突出显示时(在 Eclipse 中)状态 'Mock for type LogService named $spock_sharedField_logService',因此看起来模拟已成功注入 MyProc 实例。
我是 Spock 和 Groovy 的新手,所以我可能遗漏了一些东西,但测试不应该通过吗?在测试运行时正在调用mocks方法,所以我不明白为什么测试会报告说根本没有调用mocks方法。我是否在 MyProc 实例上初始化 mock/setting 模拟/设置交互不正确?是否有我遗漏的 Groovy 功能或注意事项?据我了解,Spock mocks 将 return 调用方法的默认值,这很好,我只是想检查此特定方法是否已作为 proc.process 的一部分被调用并进行有效交换对象
一个简单的答案是不要将@Shared 用于mocks/stubs/spies。
@Shared def proc = new MyProcessor()
def test() {
given:
def log = Mock(LogService)
proc.logService = log
when:
proc.process(new Object())
then:
1 * log.update(_)
}
现在解释:
当你 运行 你的 spec Spock 为每个测试创建一个 Specification 实例时,另外,它创建一个共享 Specification 实例来跟踪共享字段。
查看 org.spockframework.runtime.BaseSpecRunner,您将看到两个字段:
protected Specification sharedInstance;
protected Specification currentInstance;
此外,还有两个规范上下文:共享和当前。上下文保留实例、模拟上下文和模拟控制器。问题来了。当您将模拟声明为共享时,它会绑定到共享模拟控制器,但是当您声明交互('then:' 块)时,Spock 会将这些交互添加到当前模拟控制器。因此,当调用 mock 方法时(例如 logService.update(e)),Spock 检查共享模拟控制器是否允许此交互,因为您将 mock 声明为共享但在那里找不到任何东西,因为您将交互放在当前控制器。
不要使用 mock/stubs/spies 作为@Shared 字段。
我正在开发一个 Spring 引导 java 服务,其中包含一个 Camel 处理器 class,如下所示:
public class MyProc implements Processor {
@Autowired
private LogService logService;
public void process(Exchange e) {
// exchange object processing
logService.update(e)
}
}
我有以下 Spock 测试:
class MyProcTest extends Specification {
@Shared def logService = Mock(LogService)
@Shared def proc = new MyProc()
def ctx = new DefaultCamelContext()
def exch = new DefaultExchange(ctx)
void setupSpec() {
proc.logService = logService
}
def "log is updated when valid exchange is processed"() {
given:
exch.getIn().setBody(//xml string set on body)
when:
proc.process(exch)
then:
1 * logService.update(_)
}
}
当我 运行 这样做时,我遇到了一个失败,说明 1 * logService.update(_) 的调用太少(0 次调用)。我尝试调试代码,在 MyProc 中,语句被命中,并且 logService 对象在突出显示时(在 Eclipse 中)状态 'Mock for type LogService named $spock_sharedField_logService',因此看起来模拟已成功注入 MyProc 实例。
我是 Spock 和 Groovy 的新手,所以我可能遗漏了一些东西,但测试不应该通过吗?在测试运行时正在调用mocks方法,所以我不明白为什么测试会报告说根本没有调用mocks方法。我是否在 MyProc 实例上初始化 mock/setting 模拟/设置交互不正确?是否有我遗漏的 Groovy 功能或注意事项?据我了解,Spock mocks 将 return 调用方法的默认值,这很好,我只是想检查此特定方法是否已作为 proc.process 的一部分被调用并进行有效交换对象
一个简单的答案是不要将@Shared 用于mocks/stubs/spies。
@Shared def proc = new MyProcessor()
def test() {
given:
def log = Mock(LogService)
proc.logService = log
when:
proc.process(new Object())
then:
1 * log.update(_)
}
现在解释: 当你 运行 你的 spec Spock 为每个测试创建一个 Specification 实例时,另外,它创建一个共享 Specification 实例来跟踪共享字段。
查看 org.spockframework.runtime.BaseSpecRunner,您将看到两个字段:
protected Specification sharedInstance;
protected Specification currentInstance;
此外,还有两个规范上下文:共享和当前。上下文保留实例、模拟上下文和模拟控制器。问题来了。当您将模拟声明为共享时,它会绑定到共享模拟控制器,但是当您声明交互('then:' 块)时,Spock 会将这些交互添加到当前模拟控制器。因此,当调用 mock 方法时(例如 logService.update(e)),Spock 检查共享模拟控制器是否允许此交互,因为您将 mock 声明为共享但在那里找不到任何东西,因为您将交互放在当前控制器。
不要使用 mock/stubs/spies 作为@Shared 字段。