Подтвердить что ты не робот

Mockito isA (Class <T> clazz) Как разрешить безопасность типа?

в моем тесте у меня есть следующая строка:

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

isA(Iterable.class) выводит предупреждение о необходимости безотлагательного преобразования в соответствии с Iterable<Integer>. Что такое синтаксис для этого?

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

не работают.

Любые предложения?

4b9b3361

Ответ 1

Mockito/Hamcrest и общие классы

Да, это общая проблема с Mockito/Hamcrest. Обычно использование isA() с общими классами вызывает предупреждение.

Существуют предустановленные комбинации Mockito для наиболее общих классов: anyList(), anyMap(), anySet() и anyCollection().

Предложения:

anyIterable() в Mockito 2.1.0

Mockito 2.1.0 добавил новый метод anyIterable() для соответствия Iterables:

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

Игнорировать в Eclipse

Если вы просто хотите избавиться от предупреждения в Eclipse. Опция существует, поскольку Eclipse Indigo:

Окно > Настройки > Java > Компилятоp > Ошибки/предупреждения > Общие типы > Игнорировать неизбежные типичные проблемы типа

Быстрое исправление с помощью @SuppressWarnings

Я предлагаю вам сделать это, если у вас есть проблема только один раз. Я лично не помню, чтобы когда-либо понадобился isA(Iterable.class).

Как говорит Даниэль Праден, вы можете ограничить @SuppressWarnings локальной переменной или вспомогательным методом.

Использовать общий ключ isA() с TypeToken

Это решает проблему навсегда. Но у него есть два недостатка:

  • Синтаксис не слишком хорош и может смутить некоторых людей.
  • У вас есть дополнительная зависимость от библиотеки, предоставляющей класс TypeToken. Здесь я использовал TypeToken класс из Guava. Также существует класс TypeToken в Gson и a GenericType в JAX-RS.

Использование общего шаблона:

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(...);

Общий класс сопряжения:

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());
    }
}

Ответ 2

Вот что я делаю:

// Cast from Class<Iterable> to Class<Iterable<Integer>> via the raw type.
// This is provably safe due to erasure, but will generate an unchecked warning
// nonetheless, which we suppress.
@SuppressWarnings("unchecked")
Class<Iterable<Integer>> klass 
    = (Class<Iterable<Integer>>) (Class) Iterable.class;  

// later

isA(klass) // <- now this is typesafe

Ответ 3

Вы можете добавить @SuppressWarnings("unchecked") над оператором. Нет другого способа, но если это вас беспокоит, вы можете переместить бросок на вспомогательный метод.

Ответ 4

Нет никакого способа сделать это. Чтобы упростить, вы не можете инициализировать эту переменную без предупреждения:

Class<Iterable<Integer>> iterableIntegerClass = ?

Одним из решений может быть использование псевдо-typedef antipattern, , вы создаете и используете интерфейс IntegerIterable

interface IntegerIterable extends Iterable<Integer> {}

то

isA(IntegerIterable.class)

больше не будет выдавать предупреждение. Но вам придется расширить реализацию класса Iterable, чтобы они реализовали IntegerIterable:) Например:

public class IntegerArrayList extends ArrayList<Integer> implements IntegerIterable {}

Ммм вкусный...

Итак, я постараюсь, чтобы вы рассмотрели только бумагу по трещинам, добавив к вашему методу:

@SuppressWarnings("unchecked")