4

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.

  • Try with just `_` - it seems that the parameter `_ as List` is not matched correctly? – Opal Apr 08 '19 at 08:56
  • I tried it with ```_``` too, but it still gets me the same result. Even when I ommit the stubbing completely, the result is still the same: real method gets called, NPE is thrown. – Roman Abendroth Apr 08 '19 at 09:06

2 Answers2

4

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.

  • But one could change the modifier [as in this answer](https://stackoverflow.com/a/33822216/1087447) – Jazzschmidt Apr 08 '19 at 10:28
  • @Jazzschmidt yes you're right, reflection is a second option to go. – Dmytro Patserkovskyi Apr 08 '19 at 10:31
  • Thank you very much for pointing me in the right direction! It really seems that groovy has a problem with classes that are themselves not final but contain final methods. I solved the issue by creating a little facade between my class and the ```ImageAnnotatorClient``` that just serves as a proxy and can be mocked by Spock without problems. – Roman Abendroth Apr 12 '19 at 06:27
  • 1
    I had a problem like this in Kotlin, because the method was not marked with keyword "open". This response gave me the correct clue :) So keep an eye out for this in case you are using kotlin. – Lucas Andrade Mar 26 '21 at 14:04
0

In my case, I had to annotate the mocked field with SpringBean with this import;

import org.spockframework.spring.SpringBean

emrhzc
  • 1,347
  • 11
  • 19