Mockito cocok dengan argumen kelas apa pun


153

Apakah ada cara untuk mencocokkan argumen kelas dari rutin sampel di bawah ini?

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

Bagaimana saya bisa selalu mengembalikan kelas new B()apa pun yang dilewatkan method? Upaya berikut ini hanya berfungsi untuk kasus tertentu Ayang cocok.

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

EDIT : Salah satu solusinya adalah

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

6
Class<?>luar biasa!
António Almeida

Solusi Anda (Kelas <?>) Apa saja (Kelas.class) harus menjadi jawabannya di sini. Saya lebih suka menggunakannya daripada kelas ClassOrSubclassMatcher yang terlihat di bawah ini.
superbAfterSemperPhi

@superbAfterSemperPhi dan johan-sjöberg saya memposting cara lain untuk melakukan itu, tanpa pemain. Saya percaya itu bisa menjadi cara yang lebih baik. Bagaimana menurut anda?
Anmaia

Jawaban:


188

Dua cara lain untuk melakukannya (lihat komentar saya pada jawaban sebelumnya oleh @Tomasz Nurkiewicz):

Yang pertama bergantung pada fakta bahwa kompiler tidak akan membiarkan Anda memasukkan sesuatu dengan tipe yang salah:

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

Anda kehilangan pengetikan yang tepat (the Class<? extends A>) tetapi mungkin berhasil sesuai keinginan Anda.

Yang kedua jauh lebih terlibat tetapi bisa dibilang solusi yang lebih baik jika Anda benar - benar ingin memastikan bahwa argumen untuk method()adalah Aatau subkelas dari A:

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

Dimana ClassOrSubclassMatchermerupakan org.hamcrest.BaseMatcherdidefinisikan sebagai:

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

Fiuh! Saya akan menggunakan opsi pertama sampai Anda benar - benar perlu mendapatkan kontrol yang lebih baik atas apa yang method()sebenarnya dikembalikan :-)


yang if (obj instanceof Class)messes segalanya bagi saya, jadi saya dihapus.
Daniel Smith

Pada baris deklarasi kelas, saya harus berubah extends BaseMatcher<Class<T>>menjadi adil extends BaseMatcher<T>. Hanya FYI, jika orang lain mendapat kesalahan kompilasi, coba itu.
Jan

Saya juga harus mengubah matchesfungsi sebagai berikut:public boolean matches(Object obj) { if (obj != null) { return targetClass.isAssignableFrom(obj.getClass()); } return false; }
Jan

any (Class.class) mengembalikan null - bagaimana saya bisa menghindari untuk mengembalikan null
Arvind Kumar

akan lebih bagus jika benar-benar menambahkan kelas yang perlu saya impor karena sekarang banyak "ada" dari mockito
jpganz18

53

Ada cara lain untuk melakukannya tanpa pemain:

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

Solusi ini memaksa metode any()untuk mengembalikan Class<A>tipe dan bukan nilai standarnya ( Object).


5
Matcherstidak lagi digunakan dalam versi Mockito yang lebih baru dan kemungkinan akan dihapus di versi 3.0. Gunakan ArgumentMatcherssebagai gantinya:when(a.method(ArgumentMatchers.<Class<A>>any())).thenReturn(b);
Voicu

41

Jika Anda tidak tahu Paket mana yang perlu Anda impor:

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

ATAU

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

13
Ini menyelamatkan hidup saya, saya tidak sengaja mengimpor "any" dari perpustakaan hamcrest.
Gábor Nagy

3
Sekarang telah berubah menjadiorg.mockito.ArgumentMatchers.any
BOWS

27

Bagaimana tentang:

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

atau:

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

4
Ini akan dikompilasi dan berfungsi jika metode signature adalah method(A a)- tapi itu (efektif) method(Class<A> a)- jadi Anda harus menggunakan: when(a.method(isA(Class.class))).thenReturn(b);atauwhen(a.method((Class<A>) notNull())).thenReturn(b);
millhouse

bagian kedua bagi saya berfungsi sebagai pesona. berkelahi dengan (SomeClass.class) mengarah ke jalan buntu. Tapi (SomeClass.class) notNull () menyelamatkan hari saya
Vadim

Jika Anda memiliki dua metode dengan nama yang sama tetapi argumen yang berbeda, Anda dapat menyamarkan metode yang akan diejek menggunakan versi kedua di sini. Versi pertama tidak memotongnya untuk saya (di Java 8 yaitu).
Patru

Terima kasih, isA (A.class) berfungsi baik untuk saya dan mvcConversionService memilih kelas yang tepat. Ini tidak bekerja dengan (A.class) dan eq (A.class).
d3rbastl3r

9

solusi dari millhouse tidak berfungsi lagi dengan versi terbaru dari mockito

Solusi ini berfungsi dengan java 8 dan mockito 2.2.9

di mana ArgumentMatcherada 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;
    }
}

Dan penggunaannya

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

kondisi instanceof tidak diperlukan lagi, dan saya menulis metode kenyamanan:public static <T> Class<T> subClassOf(Class<T> targetClass) { return argThat(new ClassOrSubclassMatcher<>(targetClass)); }
Daniel Alder
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.