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

не работай.

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


person Mike    schedule 17.08.2012    source источник
comment
возможный дубликат Mockito.any() pass Interface with Generics   -  person Gili    schedule 27.02.2015


Ответы (4)


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

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

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

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

anyIterable() в Mockito 2.1.0

В Mockito 2.1.0 добавлен новый anyIterable() метод сопоставления итерируемых объектов:

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

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

Если вы просто хотите избавиться от предупреждения в Eclipse. Вариант существует с Затмение Индиго:

Окно > Настройки > 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());
    }
}
person Arend v. Reinersdorff    schedule 18.08.2012
comment
Возможно, лучшим API (по сравнению с набором методов anyList, anyIterable,...) было бы иметь метод T any(T). В JMockit, например, можно написать следующее, избегая непроверенного предупреждения: Iterable<Integer> col = null; client.runTask(anyString, anyString, withAny(col));. - person Rogério; 14.10.2016

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

// 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
person Daniel Pryden    schedule 17.08.2012

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

person Garrett Hall    schedule 17.08.2012
comment
Это означает: смирись с этим, нет способа сделать это без непроверенного приведения. - person Louis Wasserman; 17.08.2012
comment
Да, хотя вы можете скрыть это во вспомогательном методе, если вам от этого станет легче :P - person Garrett Hall; 17.08.2012

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

Class<Iterable<Integer>> iterableIntegerClass = ?

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

interface IntegerIterable extends Iterable<Integer> {}

тогда

isA(IntegerIterable.class)

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

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

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

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

@SuppressWarnings("unchecked")
person gontard    schedule 17.08.2012