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

не работай.

Какие-либо предложения?

4 ответа

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 > Компилятор> Ошибки / Предупреждения> Универсальные типы> Игнорировать неизбежные проблемы универсальных типов

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

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

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

Используйте универсальное сопоставление isA() с TypeToken

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

  • Синтаксис не слишком красивый и может запутать некоторых людей.
  • У вас есть дополнительная зависимость от библиотеки, предоставляющей TypeToken учебный класс. Здесь я использовал класс TypeToken из Гуавы. Там также есть TypeToken класс в Gson и 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());
    }
}

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

// 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

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

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

Class<Iterable<Integer>> iterableIntegerClass = ?

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

interface IntegerIterable extends Iterable<Integer> {}

затем

isA(IntegerIterable.class)

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

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

Ммм вкусно...

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

@SuppressWarnings("unchecked")
Другие вопросы по тегам