java - Spock 模拟验证返回 0 次调用

标签 java unit-testing spring-boot apache-camel spock

我正在处理包含 Camel 处理器类的 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 中,语句被命中,并且 logService 对象在突出显示时(在 Eclipse 中)声明“Mock for type LogService named $spock_sharedField_logService”,因此看起来模拟已成功注入(inject) MyProc 实例.

我是 Spock 和 Groovy 的新手,所以我可能遗漏了一些东西,但测试不应该通过吗?运行测试时正在调用 mocks 方法,所以我不明白为什么测试会报告 mocks 方法根本没有被调用。我是否在 MyProc 实例上初始化模拟/设置模拟/错误设置交互?是否有一些我错过的 Groovy 特性或注意事项?据我所知,Spock mocks 将在调用时从方法返回默认值,这很好,我只是想检查此特定方法是否已作为 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(_)
}

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

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

protected Specification sharedInstance;
protected Specification currentInstance;

此外,还有两个规范上下文:共享和当前。上下文保留实例、模拟上下文和模拟 Controller 。问题来了。当您将您的模拟声明为共享时,它会绑定(bind)到共享模拟 Controller ,但是当您声明交互('then:' block )时,Spock 会将这些交互添加到当前模拟 Controller 。因此,当调用 mock 方法时(例如 logService.update(e)),Spock 检查共享模拟 Controller 是否允许此交互,因为您将模拟声明为共享但在那里找不到任何东西,因为您将交互放在当前 Controller 中.

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

关于java - Spock 模拟验证返回 0 次调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41148561/

相关文章:

java - Hibernate select 查询不返回任何内容

JavaScript 单元测试 : Cannot check if jQuery method was called

unit-testing - Yii2 ActiveRecord 用 Mockery 进行模拟

java - 如何访问JWT Token然后处理请求?

java - 如何从 Java 中的麦克风获取 dB(或任何类型的音量)级别?

java 类实例变量和构造函数的问题

java - Spring配置-Arraylist的可选字段

mysql - Spring Boot 的数据源错误

java - AudioStream找不到文件Java

c# - 如何运行 TestClass 的所有单元测试及其内部 TestClass 测试?