javagroovymockingspockvision-api

Groovy Spock mock calling real method of mocked class


I am trying to write a unit test for a class that uses Google's vision API with the AnnotatorImageClient from the google-cloud-vision lib. The problem is that my mocked AnnotatorImageClient for some reason still calls the real batchAnnotateImages method and then throws a NPE, which breaks my test. I have never seen this behavior on a mock before and I'm wondering if I'm doing something wrong, if there is a bug in spock/groovy or if it has something to do with that Google lib?

I have already checked if the object used in my class is really a mock, which it is. I have tried with Spock version 1.2-groovy-2.5 and 1.3-groovy.2.5

The class that is tested:

public class VisionClient {

    private final ImageAnnotatorClient client;

    @Autowired
    public VisionClient(final ImageAnnotatorClient client) {
        this.client = client;
    }

    public Optional<BatchAnnotateImagesResponse> getLabelsForImage(final Image image) {
        var feature = Feature.newBuilder().setType(LABEL_DETECTION).build();

        var request = AnnotateImageRequest.newBuilder()
                .addFeatures(feature)
                .setImage(image)
                .build();

        return Optional.ofNullable(client.batchAnnotateImages(singletonList(request)));
}

The test:

class VisionClientSpec extends Specification {
    def "The client should use Google's client to call Vision API"() {
        given:
        def googleClientMock = Mock(ImageAnnotatorClient)
        def visionClient = new VisionClient(googleClientMock)
        def imageMock = Image.newBuilder().build()

        when:
        def resultOpt = visionClient.getLabelsForImage(imageMock)

        then:
        1 * googleClientMock.batchAnnotateImages(_ as List) >> null
        !resultOpt.isPresent()
    }
}

I would expect the mock to simply return null (I know that this test doesn't make a lot of sense). Instead, it calls com.google.cloud.vision.v1.ImageAnnotatorClient.batchAnnotateImages which throws an NPE.


Solution

  • Class ImageAnnotatorClient is written in Java, and method batchAnnotateImages(List<AnnotateImageRequest> requests) is final.

    Spock is able to mock Java final classes, but not such good in mocking Java final methods.

    You can use PowerMock to get what you need, here is tutorial how to get it work together with Spock.