Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
774 views
in Technique[技术] by (71.8m points)

java - Mockito isA(Class<T> clazz) How to resolve type safety?

in my test I have the following line:

when(client.runTask(anyString(), anyString(), isA(Iterable.class)).thenReturn(...)

isA(Iterable.class) produces warning that it needs unchecked conversion to conform to Iterable<Integer> . What is syntax for that?

isA(Iterable<Integer>.class)
isA((Iterable<Integer>)Iterable.class

do not work.

Any suggestions?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Mockito/Hamcrest and generic classes

Yes, this is a general problem with Mockito/Hamcrest. Generally using isA() with generic classes produces a warning.

There are predifined Mockito matchers for the most common generic classes: anyList(), anyMap(), anySet() and anyCollection().

Suggestions:

anyIterable() in Mockito 2.1.0

Mockito 2.1.0 added a new anyIterable() method for matching Iterables:

when(client.runTask(anyString(), anyString(), anyIterable()).thenReturn(...)

Ignore in Eclipse

If you just want to get rid of the warning in Eclipse. Option exists since Eclipse Indigo:

Window > Preferences > Java > Compiler > Errors/Warnings > Generic types > Ignore unavoidable generic type problems

Quick Fix with @SuppressWarnings

I suggest you do this if you have the problem only once. I personally don't remember ever needing an isA(Iterable.class).

As Daniel Pryden says, you can limit the @SuppressWarnings to a local variable or a helper method.

Use a generic isA() matcher with TypeToken

This solves the problem for good. But it has two disadvantages:

  • The syntax is not too pretty and might confuse some people.
  • You have an additional dependency on the library providing the TypeToken class. Here I used the TypeToken class from Guava. There's also a TypeToken class in Gson and a GenericType in JAX-RS.

Using the generic matcher:

import static com.arendvr.matchers.InstanceOfGeneric.isA;
import static org.mockito.ArgumentMatchers.argThat;

// ...

when(client.runTask(anyString(), anyString(), argThat(isA(new TypeToken<Iterable<Integer>>() {}))))
            .thenReturn(...);

Generic matcher class:

package com.arendvr.matchers;

import com.google.common.reflect.TypeToken;
import org.mockito.ArgumentMatcher;

public class InstanceOfGeneric<T> implements ArgumentMatcher<T> {
    private final TypeToken<T> typeToken;

    private InstanceOfGeneric(TypeToken<T> typeToken) {
        this.typeToken = typeToken;
    }

    public static <T> InstanceOfGeneric<T> isA(TypeToken<T> typeToken) {
        return new InstanceOfGeneric<>(typeToken);
    }

    @Override
    public boolean matches(Object item) {
        return item != null && typeToken.getRawType().isAssignableFrom(item.getClass());
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...