Groovy Spock模拟调用模拟类的真实方法

4
我正在尝试为一个使用Google Vision API 和google-cloud-vision库中的AnnotatorImageClient的类编写单元测试。问题是我的模拟AnnotatorImageClient仍然调用了真正的batchAnnotateImages方法,然后抛出了NPE,导致我的测试失败。我以前从未在模拟对象上看到过这种行为,我想知道我是否做错了什么,Spock / Groovy中是否存在错误,或者它与Google库有关?
我已经检查过我的类中使用的对象是否真的是模拟对象,而它确实是。我尝试使用Spock版本1.2-groovy-2.5和1.3-groovy-2.5进行了测试。
被测试的类:
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)));
}

测试:

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()
    }
}

我原本期望这个模拟将会返回null(我知道这个测试没有太多意义)。但实际上,它调用了com.google.cloud.vision.v1.ImageAnnotatorClient.batchAnnotateImages方法,并抛出了NPE异常。


尝试只使用'' - 似乎参数' as List'没有正确匹配? - Opal
我也尝试使用_,但结果仍然相同。即使完全省略存根,结果仍然相同:调用实际方法,抛出NPE异常。 - Roman Abendroth
2个回答

4

ImageAnnotatorClient类是用Java编写的,而方法batchAnnotateImages(List<AnnotateImageRequest> requests)final的。

Spock可以模拟Java final类,但在模拟Java final方法方面不太好。

你可以使用PowerMock来获得你需要的内容,这里是如何与Spock一起使用的教程。


但是可以更改修饰符如此答案中所示 - Jazzschmidt
@Jazzschmidt 是的,你说得对,反射是另一个选择。 - Dmytro Patserkovskyi
非常感谢您指引我正确的方向!看起来Groovy存在一个问题,即包含final方法但本身不是final的类。我通过创建一个小门面来解决这个问题,它位于我的类和ImageAnnotatorClient之间,只充当代理,并且可以轻松地被Spock模拟。 - Roman Abendroth
1
我在Kotlin中遇到了这样的问题,因为该方法没有标记关键字“open”。这个回答给了我正确的线索 :)所以,如果你正在使用Kotlin,请注意这一点。 - Lucas Andrade

0
在我的情况下,我必须使用以下导入注释模拟字段:SpringBeanimport org.spockframework.spring.SpringBean

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接