【问题标题】:Match generics with Mockito将泛型与 Mockito 匹配
【发布时间】:2015-06-22 14:36:09
【问题描述】:

我正在尝试模拟 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的泛型参数,最后定义的模拟胜过前者。

有没有办法让它工作?

【问题讨论】:

  • 可以通过创建自定义参数匹配器来实现。我知道这是可能的,但是我从来没有这样做过,所以我无法提供进一步的帮助,抱歉:((编辑:link
  • 仅供参考,始终将any(String.class) 替换为anyString()anyInt()anyFloat() 等类似...更简单、更简洁、更容易看,并且不受类型擦除。

标签: java spring unit-testing mockito


【解决方案1】:

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

替换你的:

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

与:

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

首先,Matchers.any() 不匹配类型,甚至在其any(Foo.class) 变体中也不匹配(从 Mockito 1.x 开始)。 any() 匹配 all values, including null and including incorrect types:

匹配任何对象,包括空值

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

(“未来的主要版本”可能会在 Mockito 2 中实现,其中可能会引入 isA 样式的类型检查。;参见 commentary from Mockito committer Brice。)

泛型有助于为exchangethenReturn 获取正确的参数,但由于type erasure,没有任何类型信息进入CLASS 文件,更不用说JVM。唯一断言其参数类型的 Matcher 是 isA,它采用类文字,不会帮助您处理参数化类型。

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

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

重要的是,包括ParameterizedTypeReference 在内的所有这些都支持equalshashCode,因此new ParameterizedTypeReference&lt;A&lt;B&gt;&gt;(){} 等于new ParameterizedTypeReference&lt;A&lt;B&gt;&gt;(){},即使实例不同。 (See the code here.)

因为对同一个参数化类型的引用是相等的,所以使用 Mockito 的 eq 匹配器和不同的引用,应该没问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-20
    • 1970-01-01
    • 2015-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多