我正在尝试模拟SpringRest.的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));
mock不考虑ParameterizedTypeReference
的通用参数,最后定义的mock胜过前者。
有什么办法让它发挥作用吗?
Mockito不擅长匹配泛型本身,但您的解决方案比一般情况容易得多。
更换您的:
Matchers.<ParameterizedTypeReference<SearchResultsDTO<SolrDocumentDTO>>>any())
带有:
eq(new ParameterizedTypeReference<SearchResultsDTO<SolrDocumentDTO>>() {}))
首先,Matchers.any()
与类型不匹配。在Mockito 1.x中,any(Foo.class)
甚至不匹配类型:any()
匹配所有值,包括null和不正确的类型。
匹配任何对象,包括空
这个方法不使用给定的参数进行类型检查,它只是为了避免代码中的强制转换。然而,在未来的主要版本中,这可能会发生变化(可以添加类型检查)。
(旁注:在Mockito 2及更高版本中,any(Foo.class)
具有类似英语的"any Foo"语义,使其行为更像isA(Foo.class)
。)
泛型有助于为exchange
和thenReturn
获得正确的参数,但由于类型擦除,这些类型信息都没有进入CLASS文件,更不用说JVM了。唯一断言其参数类型的Matcher是isA
,它采用类文字,对参数化类型没有帮助。
您可以编写一个自定义Matcher来检查参数的类型和类型参数,如果它们不需要擦除,但对于您的特定情况,这是不必要的。
类型擦除是ParameterizedTypeReference存在的全部原因:它将泛型信息捕获到一个子类中,其中参数化类型将不会被擦除。同样的模式用于Guava中的TypeToken或Guice中的TypeLiteral。所有这些实现都将参数化类型描述为实例。
重要的是,包括ParameterizedTypeReference在内的所有实例都支持equals
和hashCode
,因此即使实例不同,new ParameterizedTypeReference<A<B>>(){}
也等于new ParameterizedTypeReference<A<B>>(){}
。(请参阅此处的代码。)
因为对同一参数化类型的引用是相等的,所以使用Mockito的eq
匹配器和不同的引用,一切都会好起来。