Mockito соответствует любому аргументу класса


153

Есть ли способ сопоставить какой-либо аргумент класса из приведенной ниже примерной процедуры?

class A {
     public B method(Class<? extends A> a) {}
}

Как я всегда могу вернуть new B()независимо от того, в какой класс передается method? Следующая попытка работает только для конкретного случая, где Aсопоставляется.

A a = new A();
B b = new B();
when(a.method(eq(A.class))).thenReturn(b);

РЕДАКТИРОВАТЬ : одно решение

(Class<?>) any(Class.class)

6
Class<?>удивительный!
— Антонио Алмейда

Ваше (Class <?>) Любое (Class.class) решение должно быть ответом здесь. Я бы предпочел использовать его тогда, чем класс ClassOrSubclassMatcher, показанный ниже.
— superbAfterSemperPhi

@superbAfterSemperPhi и johan-sjöberg Я опубликовал еще один способ сделать это без приведения. Я считаю, что это может быть лучше. Что вы думаете?
— anmaia

Ответы:


188

Еще два способа сделать это (см. Мой комментарий к предыдущему ответу @Tomasz Nurkiewicz):

Первый основан на том факте, что компилятор просто не позволит вам передать что-то неправильного типа:

when(a.method(any(Class.class))).thenReturn(b);

Вы теряете точное печатание (the Class<? extends A>), но, вероятно, оно работает так, как вам нужно.

Второй вариант гораздо сложнее, но, возможно, это лучшее решение, если вы действительно хотите быть уверены, что аргументом method()является Aили является подклассом A:

when(a.method(Matchers.argThat(new ClassOrSubclassMatcher<A>(A.class)))).thenReturn(b);

Там , где ClassOrSubclassMatcherприведен org.hamcrest.BaseMatcherопределяется как:

public class ClassOrSubclassMatcher<T> extends BaseMatcher<Class<T>> {

    private final Class<T> targetClass;

    public ClassOrSubclassMatcher(Class<T> targetClass) {
        this.targetClass = targetClass;
    }

    @SuppressWarnings("unchecked")
    public boolean matches(Object obj) {
        if (obj != null) {
            if (obj instanceof Class) {
                return targetClass.isAssignableFrom((Class<T>) obj);
            }
        }
        return false;
    }

    public void describeTo(Description desc) {
        desc.appendText("Matches a class or subclass");
    }       
}

Уф! Я бы выбрал первый вариант, пока вам действительно не нужно получить более точный контроль над тем, что на method()самом деле возвращает :-)


что if (obj instanceof Class)портит вещи для меня, так что я удалил его.
— Даниэль Смит

В строке объявления класса мне пришлось изменить extends BaseMatcher<Class<T>>на просто extends BaseMatcher<T>. Просто к сведению, если кто-то еще получит ошибки компиляции, попробуйте это.
— Янв

Я также должен был изменить matchesфункцию на следующее:public boolean matches(Object obj) { if (obj != null) { return targetClass.isAssignableFrom(obj.getClass()); } return false; }
— Янв

any (Class.class) возвращает ноль - как я могу избежать возврата
— Арвинд Кумар

было бы здорово, если бы на самом деле добавили класс, который мне нужно импортировать, так как сейчас много «любых» из mockito
— jpganz18

53

Есть другой способ сделать это без приведения:

when(a.method(Matchers.<Class<A>>any())).thenReturn(b);

Это решение заставляет метод any()возвращать Class<A>тип, а не его значение по умолчанию ( Object).


5
Matchersустарела в новых версиях Mockito и, вероятно, будет удалена в версии 3.0. Используйте ArgumentMatchersвместо этого:when(a.method(ArgumentMatchers.<Class<A>>any())).thenReturn(b);
— Voicu

42

Если вы не знаете, какой пакет вам нужно импортировать:

import static org.mockito.ArgumentMatchers.any;
any(SomeClass.class)

ИЛИ

import org.mockito.ArgumentMatchers;
ArgumentMatchers.any(SomeClass.class)

13
Это спасло мне жизнь, я случайно импортировал "any" из библиотеки Hamcrest.
— Габор Надь

3
Теперь он изменился наorg.mockito.ArgumentMatchers.any
— BOWS

27

Как насчет:

when(a.method(isA(A.class))).thenReturn(b);

или:

when(a.method((A)notNull())).thenReturn(b);

4
Они скомпилировались бы и работали бы, если бы подпись метода была method(A a)- но это (эффективно) method(Class<A> a)- так что вам нужно было бы использовать: when(a.method(isA(Class.class))).thenReturn(b);илиwhen(a.method((Class<A>) notNull())).thenReturn(b);
— millhouse

Вторая часть для меня работает как шарм. борьба с любым (SomeClass.class) ведет в тупик. Но (SomeClass.class) notNull () спас мой день
— Вадим

Если у вас есть два метода с одним и тем же именем, но разными аргументами, вы можете устранить неоднозначность метода, который нужно смоделировать, используя вторую версию здесь. Первая версия не решила его для меня (на Java 8, то есть).
— Патру

Спасибо, isA (A.class) работает для меня просто отлично, а mvcConversionService выбирает правильный класс. Это не работает ни с одним (A.class) и eq (A.class).
— d3rbastl3r

9

Решение от Millhouse больше не работает с последней версией Mockito

Это решение работает с Java 8 и Mockito 2.2.9

где ArgumentMatcherэкземплярorg.mockito.ArgumentMatcher

public class ClassOrSubclassMatcher<T> implements ArgumentMatcher<Class<T>> {

   private final Class<T> targetClass;

    public ClassOrSubclassMatcher(Class<T> targetClass) {
        this.targetClass = targetClass;
    }

    @Override
    public boolean matches(Class<T> obj) {
        if (obj != null) {
            if (obj instanceof Class) {
                return targetClass.isAssignableFrom( obj);
            }
        }
        return false;
    }
}

И использование

when(a.method(ArgumentMatchers.argThat(new ClassOrSubclassMatcher<>(A.class)))).thenReturn(b);

условие instanceof больше не нужно, и я написал удобный метод:public static <T> Class<T> subClassOf(Class<T> targetClass) { return argThat(new ClassOrSubclassMatcher<>(targetClass)); }
— Даниэль Алдер
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.