spock 中不可预测的存根初始化

Unpredicatble stub initialization in spock

这是一个示例 spock 规范方法(我知道测试返回的存根没有意义,这只是针对此问题的简化):

def "my test"() {
   given: 
   var upload = Mock(Upload){
       waitForCompletion() >> { throw new InterruptedException() }
   }

   var transferManager = Mock(TransferManager) {
       upload(_,_,_) >> upload
   }
   
   when: 
   var up = transferManager.upload(null, null, null)
   up.waitForCompletion()  
   
   then:
   thrown(InterruptedException) 
}

我假设测试非常简单并且应该通过,但它给了我:

Expected exception of type 'java.lang.InterruptedException', but got 'java.lang.NullPointerException'

基本上,transferManager.upload() returns默认的null而不是配置的upload mock.

现在,如果我将 transferManager 初始化更改为:

   var transferManager = Mock(TransferManager)
   transferManager.upload(_,_,_) >> upload

它开始按预期工作。 在我看来,问题仅在存根使用另一个存根时才存在。比如直接使用upload stub时:

when:
upload.waitForCompletion()

它按预期工作(通过)。

此外,当我更改 transferManager 初始化以便它不使用另一个存根时:

var transferManager = Mock(TransferManager) {
    throw new InterruptedException()
}

测试也通过了。

所以我的问题是,为什么这会按预期工作:

   var transferManager = Mock(TransferManager)
   transferManager.upload(_,_,_) >> upload

虽然没有正确设置上传方法:

   var transferManager = Mock(TransferManager) {
       upload(_,_,_) >> upload
   }

?

很好,我想你发现了一个错误。

更新:我的回答完全错误,请无视。伦纳德说的完全正确(我又蠢又丑),我忽略了命名问题

我假设您使用 Spock 2.0 和 Java 10+ JDK,因为我在您的规范中看到 var 而不是 def。但结果与 def 相同,即使在 Spock 1.3 和 Groovy 2.5.

上也是如此

我为您创建了一个 MCVE and Spock issue #1351

这是因为您将变量命名为 upload,它与您要在 TransferManager 上调用的方法同名。

var upload = Mock(Upload){
  waitForCompletion() >> { throw new InterruptedException() }
}

var transferManager = Mock(TransferManager) {
  upload(_,_,_) >> upload
}

在这种情况下,局部变量比闭包委托具有更高的优先级,这就是事情出错的原因。 我认为我们在 Spock 方面无能为力,因为这就是 groovy 的工作方式。

def upload = new Upload()
def transferManager = new TransferManager()
transferManager.with {
  upload("a", "b", "c")
}

将失败 groovy.lang.MissingMethodException: No signature of method: Upload.call() is applicable for argument types: (String, String, String) values: [a, b, c]

修复该示例的最简单方法是将变量重命名为不冲突的名称。或者,您可以在存根前加上它。使其明确无误。