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