Search code examples
javakotlintestinggroovyspock

GroovySpy of a kotlin class can not be carried to java during Spock test


I am using groovy and Spock for unit test. What I want is after the line "reader.get(_ as Path, _ as String) >> fileA", I want to call reader.get() inside the Factory class and it still should return fileA. But it didn't and it just executed the real get() method.My test file is like this:

given:
def reader = GroovySpy(Reader)
def file = new File()
reader.get() >> file //For example, fileA

and:
def factory = new Factory(reader)

when:
...

In here, the Reader class is a kotlin file like this:

class Reader(
    private val repoConfig: FactStoreRepoConfiguration = FactStoreRepoConfiguration()
) {
    fun get(): File {
        //For example, by default it returns fileB
    }
}

but inside the factory, which is a java file, when I tried this:

public final class Factory implements StoreFactory {

    private final Reader reader;

    public Store create() {
        System.out.println(reader.get()); //Expect to see fileA here, but see fileB
        return new Store(reader);
    }
}

No errors were given.It should just print the file (fileA) I defined in "given" step, but it didn't and it actually executed the get method inside the Reader class and print fileB.

For debug, I added this in the test file:

given:
def reader = GroovySpy(Reader)
def file = new File(path.toString())
reader.get(_ as Path, _ as String) >> file //For example, fileA

and:
def factory = new Factory(reader)
print(factory.reader.get()) //Added to test, returns fileA here

when:
...

In the test, it print the file I set but still not work in when calling in the factory class. Is it because it is a kotlin class? Because I also mocked another java object and it still can be mocked in the factory class.


Solution

  • GroovySpy only works for Groovy code, not when called from Kotlin or Java. Furthermore, Spock can't mock final classes, which all of Kotlin classes are by default unless you open them.

    You can work around the final restriction by using spock-mockable, which can remove the final modifier for your test runtime, while keeping it in place for the compilation and in production.