Groovy Power Assert 空检查

Groovy Power Assert Null Check

我有一个 Groovy class 它接收一个参数给它的构造函数并用 Power Assert 语句检查它,如下所示:

public MyClass(Map args) {
    assert args.firstArg
}

通常 args.firstArg 的值是我项目中另一个 Groovy class 的实例。当我使用这个 class 的真实实例时,断言通过了。但是,当我使用 Spock Mocking 框架传入方法的模拟实例时,断言失败:

Assertion failed: 

assert args.firstArg
       |    |
       |    Mock for type 'OtherClass' named 'mockOtherClass'
       ['firstArg':Mock for type 'OtherClass' named 'mockOtherClass']

但是,当我将代码更改为

assert args.firstArg != null

那么我的代码就可以工作了。

直到现在,我还天真地认为

assert args.firstArg

只是 shorthand 进行空检查。

根据我在模拟 class 实例中观察到的情况,情况并非如此,我想知道是否有人可以帮助我理解其中的区别。

@hayfreed:其实我不喜欢猜测,所以请下次(或者这一次,以防我猜错)在 Whosebug 上提问时提供的不仅仅是一组不连贯的代码片段。理想情况下,提供一个 MCVE(请阅读!)。

让我们先创建一个 MCVE,好吗?

package de.scrum_master.Whosebug.q62543765

class OtherClass {}
package de.scrum_master.Whosebug.q62543765

class MyClass {
  MyClass(Map args) {
    assert args.firstArg
  }
}
package de.scrum_master.Whosebug.q62543765

import spock.lang.Specification

class MyClassTest extends Specification {
  def "do not use mock"() {
    when:
    new MyClass([firstArg: new OtherClass(), secondArg: "foo"])
    then:
    noExceptionThrown()

    when:
    new MyClass([firstArg: null, secondArg: "foo"])
    then:
    thrown AssertionError

    when:
    new MyClass([secondArg: "foo"])
    then:
    thrown AssertionError
  }

  def "use mock"() {
    when:
    new MyClass([firstArg: Mock(OtherClass), secondArg: "foo"])
    then:
    noExceptionThrown()
  }
}

本次测试通过。但是,如果我们将 OtherClass 改为集合类型呢?

package de.scrum_master.Whosebug.q62543765

class OtherClass extends ArrayList<String> {}

特征方法 not 测试失败使用 mock:

Expected no exception to be thrown, but got 'org.codehaus.groovy.runtime.powerassert.PowerAssertionError'

    at spock.lang.Specification.noExceptionThrown(Specification.java:118)
    at de.scrum_master.Whosebug.q62543765.MyClassTest.do not use mock(MyClassTest.groovy:10)
Caused by: Assertion failed: 

assert args.firstArg
       |    |
       |    []
       ['firstArg':[], 'secondArg':'foo']

    at de.scrum_master.Whosebug.q62543765.MyClass.<init>(MyClass.groovy:5)
    at de.scrum_master.Whosebug.q62543765.MyClassTest.do not use mock(MyClassTest.groovy:8)

所以你看到 Groovy truth 不仅仅是空检查。例如。如果集合为空,集合类型也会为断言产生 false

但是回到你的问题。模拟测试怎么会失败?我没有看到 OtherClass 的代码,我最好的猜测是 class 实现了一个 asBoolean 方法,正如手册中关于 Groovy 真相的部分所述:

package de.scrum_master.Whosebug.q62543765

class OtherClass {
  boolean asBoolean(){
    true
  }
}

现在测试失败看起来很像你的:

Expected no exception to be thrown, but got 'org.codehaus.groovy.runtime.powerassert.PowerAssertionError'

    at spock.lang.Specification.noExceptionThrown(Specification.java:118)
    at de.scrum_master.Whosebug.q62543765.MyClassTest.use mock(MyClassTest.groovy:28)
Caused by: Assertion failed: 

assert args.firstArg
       |    |
       |    Mock for type 'OtherClass'
       ['firstArg':Mock for type 'OtherClass', 'secondArg':'foo']

    at de.scrum_master.Whosebug.q62543765.MyClass.<init>(MyClass.groovy:5)
    at de.scrum_master.Whosebug.q62543765.MyClassTest.use mock(MyClassTest.groovy:26)

你会如何解决这个问题?只需将 asBoolean 方法存根到 return true:

  def "use mock"() {
    given:
    def otherClass = Mock(OtherClass) {
      asBoolean() >> true
    }
    when:
    new MyClass([firstArg: otherClass, secondArg: "foo"])
    then:
    noExceptionThrown()
  }