将泛型与 Mockito 匹配

2022-09-03 18:27:01

我试图嘲笑Spring Rest的方法。restTemplate.exchange

在同一个测试中,我有多个调用,这些调用仅因返回类型而异。

以下是我创建的模拟的方法

第一

// Original method
restTemplate.exchange(UrlMap.SEARCH + '?' + searchDocsForm.toQueryParams(),
            HttpMethod.GET, null, new ParameterizedTypeReference<SearchResultsDTO<SolrDocumentDTO>>() {
            })
// Mock
when(restTemplate.exchange(any(String.class), any(HttpMethod.class), any(), Matchers.<ParameterizedTypeReference<SearchResultsDTO<SolrDocumentDTO>>>any())).thenReturn(
            new ResponseEntity<>(searchResultsDTO, HttpStatus.OK));

第二

// Original method
restTemplate.exchange(UrlMap.ALL_DOCUS_TOPICS,
            HttpMethod.GET, null, new ParameterizedTypeReference<List<SelectItem>>() {
            }).getBody();
// Mock
when(restTemplate.exchange(any(String.class), any(HttpMethod.class), any(), Matchers.<ParameterizedTypeReference<List<SelectItem>>>any())).thenReturn(
            new ResponseEntity<>(selectItems, HttpStatus.OK));

模拟不考虑 的一般参数,最后定义的模拟优先于前者。ParameterizedTypeReference

有什么办法可以让它工作吗?


答案 1

Mockito不擅长匹配泛型本身,但你的解决方案比一般情况容易得多。

替换您的:

Matchers.<ParameterizedTypeReference<SearchResultsDTO<SolrDocumentDTO>>>any())

跟:

eq(new ParameterizedTypeReference<SearchResultsDTO<SolrDocumentDTO>>() {}))

首先,不匹配类型,甚至在其种类上也不匹配(截至Mockito 1.x)。 匹配所有值,包括 null 和不正确的类型Matchers.any()any(Foo.class)any()

匹配任何对象,包括空值

此方法不使用给定参数进行类型检查,它只是为了避免在代码中强制转换。但是,这可能会在未来的主要版本中发生变化(可以添加类型检查)。

(Mockito 2的“未来主要版本”可能会成真,其中可能会引入-style类型检查。参见Mockito提交者Brice的评论isA

泛型有助于获取 和 的正确参数,但由于类型擦除,这些类型信息都不会进入 CLASS 文件,更不用说 JVM 了。唯一断言其参数类型的 Matcher 是 isA,它采用类文本,对于参数化类型不会有所帮助。exchangethenReturn

您可以编写一个自定义 Matcher 来检查参数的类型和类型参数(如果它们不受擦除的影响),但对于您的特定情况,这不是必需的。

类型擦除是 ParameterizedTypeReference 存在的全部原因:它将泛型信息捕获到子类中,其中参数化类型不会被擦除。同样的模式用于番石榴中的TypeToken或Guice中的TypeLiteral。所有这些实现都将参数化类型描述为实例

重要的是,它们(包括 ParameterizedTypeReference)都支持 和 ,因此即使实例不同,它们也相等。(请参阅此处的代码。equalshashCodenew ParameterizedTypeReference<A<B>>(){}new ParameterizedTypeReference<A<B>>(){}

由于对相同参数化类型的引用是相等的,因此将 Mockito 的匹配器与不同的引用一起使用,事情应该没问题。eq


答案 2

推荐