带有 Spock Stub 的泛型

Generics with Spock Stub

我无法为通用 class 编译 Spock 存根。构造函数的签名如下:

SomeClass(SerSup<Cap> capSup, String foo, String bar);

我需要存根第一个参数。以下是我失败的尝试。

第一次尝试:

def someClass = new SomeClass(Stub(SerSup<Cap>), "foo", "bar")

Error: Groovyc: unexpected token: >
Status bar: ',' or ')' expected

再试一次:

def someClass = new someClass(Stub(Cup) as SerSup<Cup>, "foo" ,"bar")

groovy.lang.MissingMethodException: No signature of method: com.sun.proxy.$Proxy10.get() is applicable for argument types: () values: []
Possible solutions: grep(), getAt(java.lang.String), grep(java.lang.Object), wait(), any(), wait(long)

at loom.SomeClass.SomeMethod(SomeClassTest.groovy:14)

存根 SomeClass 构造函数的第一个参数的正确方法是什么?

您的第二次尝试失败,因为您无法将 Stub(Cap) 转换为 SerSup<Cap>。您将不得不 Stub(SerSup),或者您可以应用我在下面描述的建议。

我建议在初始化 SomeClass 之前为存根创建一个变量。您可以使用 Stub(type: ...) 构造函数存根通用 class,例如

SerSup<String> serSup = Stub(type: new TypeToken<SerSup<String>>(){}.type) as SerSup<String>

此初始化不会在您的 IDE 中产生任何警告。如果您对一些警告没有意见,您可以将其简化为:

def serSup = Stub(type: new TypeToken<SerSup<String>>(){}.type)

或者,您可以尝试类似的操作:

SerSup<String> serSup = Stub(SerSup) {
    get() >> ""
}

此替代解决方案需要将方法存根到 return 有效类型,否则它 return 等同于 new Object()。在第一种情况下,“默认”值是 returned,因为我们满足所有类型检查(例如,在 String 的情况下,空字符串 returned)。

下面是一个展示这两种方法的例子:

import com.google.common.reflect.TypeToken
import spock.lang.Specification

class StubSpec extends Specification {

    def "test stubbing with default value for String"() {
        when:
        SerSup<String> serSup = Stub(type: new TypeToken<SerSup<String>>(){}.type) as SerSup<String>

        then:
        serSup.get() == ""
    }

    def "test stubbing without explicit type"() {
        when:
        SerSup<String> serSup = Stub(SerSup) {
            get() >> "lorem ipsum"
        }

        then:
        serSup.get() == "lorem ipsum"
    }

    static class SerSup<T> {
        private final T obj

        SerSup(T t) {
            this.obj = t
        }

        T get() {
            return obj
        }
    }
}