Cara mencocokkan vararg dengan benar di Mockito


152

Saya sudah mencoba untuk mengejek metode dengan parameter vararg menggunakan Mockito:

interface A {
  B b(int x, int y, C... c);
}

A a = mock(A.class);
B b = mock(B.class);

when(a.b(anyInt(), anyInt(), any(C[].class))).thenReturn(b);
assertEquals(b, a.b(1, 2));

Ini tidak berfungsi, namun jika saya melakukan ini sebagai gantinya:

when(a.b(anyInt(), anyInt())).thenReturn(b);
assertEquals(b, a.b(1, 2));

Ini berhasil, meskipun begitu saya telah sepenuhnya menghilangkan argumen varargs ketika mematikan metode.

Ada petunjuk?


fakta bahwa contoh terakhir berfungsi agak sepele karena cocok dengan kasus ketika nol parameter vararg lewat.
topchef

Jawaban:


235

Mockito 1.8.1 memperkenalkan pencocokan anyargar () :

when(a.b(anyInt(), anyInt(), Matchers.<String>anyVararg())).thenReturn(b);

Lihat juga riwayat untuk ini: https://code.google.com/archive/p/mockito/issues/62

Edit sintaks baru setelah penghentian:

when(a.b(anyInt(), anyInt(), ArgumentMatchers.<String>any())).thenReturn(b);

26
anyVararg()memiliki Object sebagai tipe pengembaliannya. Untuk membuatnya kompatibel dengan semua jenis var arg (mis. String ..., Integer ..., dll.), Lakukan casting secara eksplisit. Misalnya, jika sudah, doSomething(Integer number, String ... args)Anda dapat melakukan kode tiruan / rintisan dengan sesuatu seperti when(mock).doSomething(eq(1), (String) anyVarargs()). Itu harus mengurus kesalahan kompilasi.
Psycho Punch

15
untuk info anyVararg sekarang sudah tidak digunakan lagi: "@deprecated mulai dari 2.1.0 use any ()"
alexbt

5
Matcherssekarang tidak digunakan lagi untuk menghindari benturan nama dengan org.hamcrest.Matcherskelas dan kemungkinan akan dihapus di mockito v3.0. Gunakan ArgumentMatcherssebagai gantinya.
JonyD

31

Fitur yang agak tidak berdokumen: Jika Anda ingin mengembangkan Pencocokan khusus yang cocok dengan argumen vararg, Anda harus menerapkannya org.mockito.internal.matchers.VarargMatcheragar dapat berfungsi dengan benar. Ini adalah antarmuka marker kosong, yang tanpanya Mockito tidak akan membandingkan argumen dengan benar saat menggunakan metode dengan varargs menggunakan Matcher Anda.

Sebagai contoh:

class MyVarargMatcher extends ArgumentMatcher<C[]> implements VarargMatcher {
    @Override public boolean matches(Object varargArgument) {
        return /* does it match? */ true;
    }
}

when(a.b(anyInt(), anyInt(), argThat(new MyVarargMatcher()))).thenReturn(b);

7

Membangun jawaban Eli Levine di sini adalah solusi yang lebih umum:

import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.mockito.ArgumentMatcher;
import org.mockito.internal.matchers.VarargMatcher;

import static org.mockito.Matchers.argThat;

public class VarArgMatcher<T> extends ArgumentMatcher<T[]> implements VarargMatcher {

    public static <T> T[] varArgThat(Matcher<T[]> hamcrestMatcher) {
        argThat(new VarArgMatcher(hamcrestMatcher));
        return null;
    }

    private final Matcher<T[]> hamcrestMatcher;

    private VarArgMatcher(Matcher<T[]> hamcrestMatcher) {
        this.hamcrestMatcher = hamcrestMatcher;
    }

    @Override
    public boolean matches(Object o) {
        return hamcrestMatcher.matches(o);
    }

    @Override
    public void describeTo(Description description) {
        description.appendText("has varargs: ").appendDescriptionOf(hamcrestMatcher);
    }

}

Maka Anda bisa menggunakannya dengan pencocokan array hamcrest sebagai berikut:

verify(a).b(VarArgMatcher.varArgThat(
            org.hamcrest.collection.IsArrayContaining.hasItemInArray("Test")));

(Jelas impor statis akan membuat ini lebih mudah dibaca.)


Bagus. Ini harus dibangun ke IMO Mockito.
bryant

Saya mengajukan masalah terhadap Hamcrest untuk menambahkan sesuatu seperti ini. Lihat github.com/mockito/mockito/issues/356
Mark

Apakah ini untuk Mockito 1? Saya mendapatkan berbagai kesalahan kompilasi ketika mencoba melakukan kompilasi terhadap 2.10.
Frans

@ Trans sepertinya rilis 2 masih dalam versi beta ketika saya menulis jawaban ini, jadi ya itu mungkin ditulis untuk Mockito v1.10.19 atau sekitar itu. ( github.com/mockito/mockito/releases ) Mungkin bisa diperbarui ... :-D
Peter Westmacott

3

Saya telah menggunakan kode dalam jawaban Peter Westmacott namun dengan Mockito 2.2.15 sekarang Anda dapat melakukan hal berikut:

verify(a).method(100L, arg1, arg2, arg3)

dimana arg1, arg2, arg3varargs


1

Membangun jawaban topchef,

Untuk 2.0.31-beta saya harus menggunakan Mockito.anyVararg alih-alih Matchers.anyVararrg:

when(a.b(anyInt(), anyInt(), Mockito.<String>anyVararg())).thenReturn(b);

3
untuk info anyVararg sekarang sudah tidak digunakan lagi: "@deprecated mulai dari 2.1.0 use any ()"
alexbt

0

Dalam kasus saya, tanda tangan dari metode yang ingin saya tangkap argumennya adalah:

    public byte[] write(byte ... data) throws IOException;

Dalam hal ini Anda harus menggunakan array byte secara eksplisit:

       when(spi.write((byte[])anyVararg())).thenReturn(someValue);

Saya menggunakan versi mockito 1.10.19


0

Anda juga dapat mengulang argumen:

Object[] args = invocation.getArguments(); 
for( int argNo = 0; argNo < args.length; ++argNo) { 
    // ... do something with args[argNo] 
}

misalnya memeriksa tipenya dan melemparkannya secara tepat, menambah daftar atau apa pun.


0

Mengadaptasi jawaban dari @topchef,

Mockito.when(a.b(Mockito.anyInt(), Mockito.anyInt(), Mockito.any())).thenReturn(b);

Per dokumen java untuk Mockito 2.23.4, Mockito.any () "Cocok dengan apa pun, termasuk null dan varargs."


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.