Java Spock mock verify返回0个调用

Java Spock mock verify返回0个调用,java,unit-testing,spring-boot,apache-camel,spock,Java,Unit Testing,Spring Boot,Apache Camel,Spock,我正在使用Spring Boot java服务,该服务包含一个驼峰处理器类,如下所示: public class MyProc implements Processor { @Autowired private LogService logService; public void process(Exchange e) { // exchange object processing logService.update(e

我正在使用Spring Boot java服务,该服务包含一个驼峰处理器类,如下所示:

public class MyProc implements Processor {

    @Autowired
    private LogService logService;

    public void process(Exchange e) {
            // exchange object processing
            logService.update(e)
        }   
}
我有下面的斯波克测试:

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\u sharedField\u logService”,因此看起来Mock已成功注入MyProc实例


我是斯波克和Groovy的新手,所以我可能遗漏了一些东西,但测试不应该通过吗?mocks方法在测试运行时被调用,所以我不明白为什么测试报告mocks方法根本没有被调用。我是否初始化模拟/在MyProc实例上设置模拟/设置交互不正确?是否有一些我错过的Groovy特性或警告?据我所知,Spock mocks在调用时将从一个方法返回一个默认值,这很好,我只想检查这个特定的方法是否作为proc.process的一部分使用了一个有效的exchange对象进行了调用

@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会为每个测试创建一个规范实例,另外,它还会创建一个共享规范实例来跟踪共享字段

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

protected Specification sharedInstance;
protected Specification currentInstance;
此外,有两个规范上下文:共享和当前。上下文保留实例、模拟上下文和模拟控制器。问题来了。当您将模拟声明为共享时,它将绑定到共享模拟控制器,但当您声明交互('then:'block)时,Spock会将这些交互添加到当前模拟控制器。因此,当调用mock方法(例如logService.update(e))时,Spock会检查是否允许与共享mock控制器进行此交互,因为您将此交互放置在当前控制器中,因此您将该mock声明为共享,但在其中找不到任何内容


不要将mock/stubs/spies用作@Shared字段。

一般来说,字段注入有问题——尽可能使用构造函数注入。如果删除
@Shared
,会发生什么?看起来您只实例化了一次mock(通常每个方法都会重置它),但每次都会重建上下文。这种不匹配可能会导致问题。删除shared并切换到void setup()vs setupSpec是有效的,谢谢。因此我认为每个feature方法都会获得自己的实例字段副本,这难道不意味着每个测试都有一个新版本的proc和logService吗?
@shared
明确表示“不要为每个功能方法创建新副本”。或者至少是Spock Mock。仍然有一些边缘情况(例如Spring上下文注入)需要使用Mockito mocks.twitch