Match generics with Mockito

后端 未结 1 2002
谎友^
谎友^ 2021-01-04 21:20

I\'m trying to mock the restTemplate.exchange method of Spring Rest.

In the same test I have multiple calls which differ only by the return type.

<
相关标签:
1条回答
  • 2021-01-04 21:55

    Mockito isn't good at matching generics itself, but your solution is much easier than the general case.

    Replace your:

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

    with:

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

    First of all, Matchers.any() doesn't match type, not even in its any(Foo.class) variety (as of Mockito 1.x). any() matches all values, including null and including incorrect types:

    Matches any object, including nulls

    This method doesn't do type checks with the given parameter, it is only there to avoid casting in your code. This might however change (type checks could be added) in a future major release.

    (The "future major release" may come true for Mockito 2, where isA-style type checks may be introduced. ; See commentary from Mockito committer Brice.)

    The generics are helpful to get the right parameter for exchange and thenReturn, but because of type erasure none of that type information makes it into the CLASS file, let alone the JVM. The only Matcher that asserts the type of its argument is isA, which takes a class literal and won't help you for parameterized types.

    You could write a custom Matcher that inspects an argument's type and type parameters, if they aren't subject to erasure, but for your specific case that's not necessary.

    Type erasure is the whole reason ParameterizedTypeReference exists: It captures the generics information into a subclass, where the parameterized type will not be erased. This same pattern is used for TypeToken in Guava or TypeLiteral in Guice. All of these implementations describe a parameterized type as an instance.

    Importantly, all of them—including ParameterizedTypeReference—support equals and hashCode, so new ParameterizedTypeReference<A<B>>(){} equals new ParameterizedTypeReference<A<B>>(){} even though the instances are different. (See the code here.)

    Because references to the same parameterized type are equal, use Mockito's eq matcher with a different reference, and things should be fine.

    0 讨论(0)
提交回复
热议问题