小编典典

Spock模拟验证返回0调用

spring-boot

我正在使用包含骆驼处理器类的Spring Boot Java服务,如下所示:

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中命中了该语句,并且突出显示了(在Eclipse中)logService对象状态为“名为$
spock_sharedField_logService类型的LogService类型的模拟”,因此看起来该模拟已成功注入到MyProc实例中。

我是Spock和Groovy的新手,所以我可能会缺少一些东西,但是测试不应该通过吗?运行测试时将调用模拟方法,因此我不理解为什么测试会报告完全没有调用模拟方法。我是否在MyProc实例上初始化模拟/设置模拟/错误地设置交互?我错过了一些Groovy功能或警告吗?据我了解,Spock模拟会在调用时从方法中返回默认值,这很好,我只想检查此特定方法是否已作为带有有效交换对象的proc.process的一部分被调用。


阅读 295

收藏
2020-05-30

共1个答案

小编典典

一个简单的答案是不要对模拟/存根/间谍使用@Shared。

@Shared def proc = new MyProcessor()

def test() {
    given:
    def log = Mock(LogService)
    proc.logService = log

    when:
    proc.process(new Object())

    then:
    1 * log.update(_)
}

现在说明:运行规范时,Spock会为每个测试创建一个Specification实例,此外,它还会创建一个共享的Specification实例来跟踪共享字段。

查看org.spockframework.runtime.BaseSpecRunner,您将看到两个字段:

protected Specification sharedInstance;
protected Specification currentInstance;

此外,有两个规范上下文:共享和当前。上下文保留实例,模拟上下文和模拟控制器。问题来了。当您宣布模拟共享时,它绑定到共享模拟控制器,但是当您拒绝交互(“
then:”块)时,Spock会将这些交互添加到当前的模拟控制器中。因此,当调用模拟方法(例如logService.update(e))时,Spock会检查是否允许与共享模拟控制器进行此交互,因为您将模拟声明为共享但未在其中找到任何东西,因为您已将交互置于当前控制器中。

不要将模拟/存根/间谍用作@Shared字段。

2020-05-30