Loom
Loom

Reputation: 9986

Generics with Spock Stub

I cannot make compile Spock stub for generic class. The signature of constructor is following:

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

I need to stub the first argument. The following are my failed attempts.

First try:

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

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

Another try:

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)

What is the right way to stub first argument of SomeClass constructor?

Upvotes: 4

Views: 3184

Answers (1)

Szymon Stepniak
Szymon Stepniak

Reputation: 42224

Your second attempt failed because you cannot cast Stub(Cap) to SerSup<Cap>. You would have to Stub(SerSup) instead, or you could apply the suggestions I have described below.

I would recommend creating a variable for your stub before initializing SomeClass. You can stub generic class using Stub(type: ...) constructor, e.g.

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

This initialization does not produce any warning in your IDE. If you are ok with some warnings you can simplify it to:

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

Alternatively, you could try something like:

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

This alternative solution requires stubbing methods to return valid type, otherwise it returns the equivalent of new Object(). In the first case, "default" values are returned, because we satisfied all type checks (e.g. in case of a String, an empty string returned).

Here is an example that shows both approaches:

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
        }
    }
}

Upvotes: 6

Related Questions