1
votes

Can somebody tell me if this is a bug or intended behavior.

I know in Spock I can test private methods:

def "test with private"() {
    given:
        FileContentValidator fileContentValidator = new FileContentValidator(1)

    when:
        fileContentValidator.validateCustomerSiteId("") // this is a private method

    then:
        true // succeeds
}

But when I try the same thing using a Spock Spy, it fails:

def "test with private on spy"() {
    given:
        FileContentValidator fileContentValidator = Spy(FileContentValidator, constructorArgs: [1])

    when:
        fileContentValidator.validateCustomerSiteId("") // this is a private method

    then:
        true // does not get here
}

I get an exception:

groovy.lang.MissingMethodException: No signature of method: com.shoppertrak.device.management.web.validator.ophour.FileContentValidator$$EnhancerByCGLIB$$7ff6a42.validateCustomerSiteId() is applicable for argument types: (java.lang.String) values: []

1
Seems rash to call it a bug. A spy's job is to spy on the methods in the contract, which is a flexible concept, but hard to find a definition that includes things that are declared to be private. - Nathan Hughes
Then perhaps that puts it in the "intended behavior" category - mikhail
Is FileContentValidator a class type or is it an interface type? A spy is always based on a real object you must provide a class type rather than an interface type. - Kalenda
FileContentValidator is a class - mikhail
Try changing the method to protected. - Kalenda

1 Answers

1
votes

I think this is due to how the cglib works. When testing an existing concrete class, Spock doesn't get involved in the byte code, so you're taking advantage of a flaw in Groovy that give you access to private methods. When you spy or mock the same class, the Spock/cglib manipulation steps in and changes the resulting byte code. The end product is a method that is truly private, thus you can't access it.

There are probably hacks you can use to get around it, but you're probably better off adding something like a CustomerSiteIdValidator class with a public validateCustomerSiteId() that gets injected into your FileContentValidator class. Then you can easily mock it and isolate responsibilities.

Someone suggested adding the ability to Spy private methods, but the ticket was closed as Won't Fix https://github.com/spockframework/spock/issues/403