Mockito passt jedes Klassenargument an

Lesezeit: 6 Minuten

Benutzer-Avatar
Johan Sjöberg

Gibt es eine Möglichkeit, ein Klassenargument der folgenden Beispielroutine abzugleichen?

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

Wie kann ich stets Rückkehr a new B() unabhängig davon, in welche Klasse übergegangen wird method? Der folgende Versuch funktioniert nur für den speziellen Fall, wo A Ist abgestimmt.

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

BEARBEITEN: Eine Lösung ist

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

  • Class<?> toll!

    – António Almeida

    9. April 2014 um 19:27 Uhr

  • Ihre (Class) any(Class.class)-Lösung sollte hier die Antwort sein. Ich würde das viel lieber verwenden als die Klasse ClassOrSubclassMatcher, die unten zu sehen ist.

    – superbAfterSemperPhi

    26. Mai 2015 um 17:12 Uhr

  • @superbAfterSemperPhi und johan-sjöberg Ich habe einen anderen Weg gepostet, ohne Besetzung. Ich glaube, das könnte ein besserer Weg sein. Was denkst du?

    – anmaia

    13. Januar 2016 um 18:37 Uhr

Benutzer-Avatar
Mühle

Zwei weitere Möglichkeiten, dies zu tun (siehe meinen Kommentar zur vorherigen Antwort von @Tomasz Nurkiewicz):

Die erste beruht auf der Tatsache, dass der Compiler Sie einfach nicht etwas vom falschen Typ übergeben lässt:

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

Sie verlieren die genaue Eingabe (die Class<? extends A>), aber es funktioniert wahrscheinlich so, wie Sie es brauchen.

Die zweite ist viel aufwendiger, aber für Sie wohl die bessere Lösung Ja wirklich wollen sicher sein, dass das Argument zu method() ist ein A oder eine Unterklasse von A:

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

Wo ClassOrSubclassMatcher ist ein org.hamcrest.BaseMatcher definiert als:

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

Puh! Ich würde mit der ersten Option gehen, bis Sie Ja wirklich müssen eine feinere Kontrolle darüber bekommen, was method() tatsächlich zurück 🙂

  • das if (obj instanceof Class) bringt mich durcheinander, also habe ich es entfernt.

    – Daniel Schmidt

    24. Oktober 2014 um 4:22 Uhr

  • Auf der Deklarationszeile der Klasse musste ich mich ändern extends BaseMatcher<Class<T>> zu einfach extends BaseMatcher<T>. Nur zu Ihrer Information, wenn jemand anderes Kompilierungsfehler bekommt, probieren Sie das aus.

    – Jan

    26. Juli 2017 um 21:09 Uhr

  • Die musste ich auch wechseln matches Funktion zu folgendem: public boolean matches(Object obj) { if (obj != null) { return targetClass.isAssignableFrom(obj.getClass()); } return false; }

    – Jan

    26. Juli 2017 um 21:13 Uhr

  • any(Class.class) gibt null zurück – wie kann ich vermeiden, null zurückzugeben

    – Arvind Kumar

    23. August 2019 um 11:35 Uhr

  • Wäre toll, wenn ich tatsächlich die Klasse hinzufügen würde, die ich importieren muss, da jetzt viele “irgendwelche” von mockito sind

    – jpganz18

    2. September 2019 um 13:05 Uhr

Es gibt eine andere Möglichkeit, dies ohne Besetzung zu tun:

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

Diese Lösung erzwingt das Verfahren any() zurückgeben Class<A> Typ und nicht sein Standardwert (Object).

  • Matchers ist in neueren Versionen von Mockito veraltet und wird wahrscheinlich in Version 3.0 entfernt. Verwenden ArgumentMatchers stattdessen: when(a.method(ArgumentMatchers.<Class<A>>any())).thenReturn(b);

    – Voicu

    20. September 2018 um 23:19 Uhr

  • Danke, hat perfekt funktioniert!

    – Gustavo Amaro

    11. Februar um 16:53 Uhr

  • Perfekt, die Matchers. >any() ist hier die Spezialsauce! Damit können Sie eine Klasse dieses Typs abgleichen.

    – Jason D

    10. Juni um 14:47 Uhr

Benutzer-Avatar
Joao Luiz Cadore

Wenn Sie keine Ahnung haben, welches Paket Sie importieren müssen:

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

ODER

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

  • Das hat mir das Leben gerettet, ich habe versehentlich “beliebige” aus der Hamcrest-Bibliothek importiert.

    – Gabor Nagy

    27. Februar 2017 um 13:43 Uhr

  • Jetzt hat es sich geändert org.mockito.ArgumentMatchers.any

    – BÖGEN

    27. August 2018 um 10:38 Uhr

  • Es gab 3 andere mögliche Pakete, alle vernünftig, die ich hätte auswählen können. Ich wünschte, mehr Leute hätten den Paketnamen angegeben. Vielen Dank.

    – Holzfäller

    30. August 2021 um 23:07 Uhr

Wie wäre es mit:

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

oder:

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

Die Lösung von Millhouse funktioniert nicht mehr mit der neuesten Version von Mockito

Diese Lösung funktioniert mit Java 8 und Mockito 2.2.9

wo ArgumentMatcher ist eine Instanz von 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;
    }
}

Und der Einsatz

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

  • Die Instanz der Bedingung ist nicht mehr erforderlich, und ich habe eine bequeme Methode geschrieben: public static <T> Class<T> subClassOf(Class<T> targetClass) { return argThat(new ClassOrSubclassMatcher<>(targetClass)); }

    – Daniel Alder

    3. Februar 2020 um 13:48 Uhr

Benutzer-Avatar
Marian Klühspies

Keines der obigen Beispiele hat bei mir funktioniert, da ich eine Methode mehrmals für verschiedene Klassentypparameter nachahmen muss.

Stattdessen funktioniert dies.

//Handle InstrumentType.class
Mockito.doReturn(new InstrumentTypeMapper() {
    @Override
    public InstrumentType map(String sourceType) throws Exception {
        return InstrumentType.Unknown;
    }
}).when(mappingLoader).load(any(ServiceCode.class), argThat(new ArgumentMatcher<Class<InstrumentType>>() {
    @Override
    public boolean matches(Class<InstrumentType> argument) {
        return InstrumentType.class.isAssignableFrom(argument);
    }
}));

//Handle InstrumentSubType.class    
Mockito.doReturn(new InstrumentSubTypeMapper() {
    @Override
    public InstrumentSubType map(String sourceType) throws Exception {
        return InstrumentSubType.istNone;
    }
}).when(mappingLoader).load(any(ServiceCode.class), argThat(new ArgumentMatcher<Class<InstrumentSubType>>() {
    @Override
    public boolean matches(Class<InstrumentSubType> argument) {
        return InstrumentSubType.class.isAssignableFrom(argument);
    }
}));

Das ist die Kurzfassung:

Mockito.doReturn(new InstrumentTypeMapper() {
    @Override
    public InstrumentType map(String sourceType) throws Exception {
        return InstrumentType.Unknown;
    }
}).when(mappingLoader).load(any(ServiceCode.class), argThat((ArgumentMatcher<Class<InstrumentType>>) InstrumentType.class::isAssignableFrom));

Mockito.doReturn(new InstrumentSubTypeMapper() {
    @Override
    public InstrumentSubType map(String sourceType) throws Exception {
        return InstrumentSubType.istNone;
    }
}).when(mappingLoader).load(any(ServiceCode.class), argThat((ArgumentMatcher<Class<InstrumentSubType>>) InstrumentSubType.class::isAssignableFrom));

Wie Sie sehen können, verwende ich benutzerdefinierte ArgumentMatcher zusammen mit argDasnicht sicher, ob es einen kürzeren Weg gibt, der auch funktioniert.

  • Die Instanz der Bedingung ist nicht mehr erforderlich, und ich habe eine bequeme Methode geschrieben: public static <T> Class<T> subClassOf(Class<T> targetClass) { return argThat(new ClassOrSubclassMatcher<>(targetClass)); }

    – Daniel Alder

    3. Februar 2020 um 13:48 Uhr

1351720cookie-checkMockito passt jedes Klassenargument an

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy