Мокіто відповідає будь-якому аргументу класу


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

EDIT : Одне рішення

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

6
Class<?>дивовижний!
António Almeida

Тут слід відповісти на ваше (Class <?>) Будь-яке (Class.class) рішення. Я б набагато скоріше скористався цим класом ClassOrSubclassMatcher, показаним нижче.
superbAfterSemperPhi

@superbAfterSemperPhi та johan-sjöberg Я опублікував інший спосіб зробити це, без ролі. Я вважаю, що це може бути кращим способом. Що ти думаєш?
anmaia

Відповіді:


188

Ще два способи зробити це (дивіться мій коментар до попередньої відповіді від @Tomasz Nurkiewicz):

Перший покладається на те, що компілятор просто не дозволить вам передати щось неправильне:

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

Ви втрачаєте точне введення тексту ( 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>. Просто FYI, якщо хтось інший отримує помилки компіляції, спробуйте це.
січня

Я також мав змінити matchesфункцію до наступного:public boolean matches(Object obj) { if (obj != null) { return targetClass.isAssignableFrom(obj.getClass()); } return false; }
Jan

будь-який (Class.class) повертає null - як я можу уникнути повернення нуля
Arvind Kumar

Було б чудово, якщо насправді додати клас, який мені потрібно імпортувати, оскільки зараз багато "будь-якого" з 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

41

Якщо ви не знаєте, який пакунок потрібно імпортувати:

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

АБО

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

13
Це врятувало мені життя, я випадково імпортував "будь-яке" з бібліотеки hamcrest.
Gábor Nagy

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є instanceoforg.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);

caseof умова більше не потрібна, і я написав зручний метод: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.