Menggunakan metode “any ()” generik Mockito

194

Saya memiliki antarmuka dengan metode yang mengharapkan array Foo:

public interface IBar {
  void doStuff(Foo[] arr);
}

Saya mengejek antarmuka ini menggunakan Mockito, dan saya ingin menegaskan yang doStuff()dipanggil, tapi saya tidak ingin memvalidasi argumen apa yang diloloskan - "tidak peduli".

Bagaimana cara menulis kode berikut menggunakan any() , metode generik, bukan anyObject()?

IBar bar = mock(IBar.class);
...
verify(bar).doStuff((Foo[]) anyObject());
ripper234
sumber

Jawaban:

111

Karena Java 8 Anda dapat menggunakan metode argumen-kurang anydan argumen tipe akan disimpulkan oleh kompiler:

verify(bar).doStuff(any());

Penjelasan

Hal baru di Java 8 adalah bahwa tipe target ekspresi akan digunakan untuk menyimpulkan parameter tipe sub-ekspresi. Sebelum Java 8 hanya argumen untuk metode yang digunakan untuk tipe inferensi parameter (sebagian besar waktu).

Dalam hal ini tipe parameter doStuffakan menjadi tipe target untuk any(), dan tipe nilai pengembalian any()akan dipilih untuk mencocokkan tipe argumen itu.

Mekanisme ini ditambahkan di Java 8 terutama untuk dapat mengkompilasi ekspresi lambda, tetapi umumnya meningkatkan inferensi tipe.


Tipe primitif

Sayangnya, ini tidak berfungsi dengan tipe primitif:

public interface IBar {
    void doPrimitiveStuff(int i);
}

verify(bar).doPrimitiveStuff(any()); // Compiles but throws NullPointerException
verify(bar).doPrimitiveStuff(anyInt()); // This is what you have to do instead

Masalahnya adalah bahwa kompiler akan menyimpulkan Integersebagai nilai balik dari any(). Mockito tidak akan mengetahui hal ini (karena tipe penghapusan) dan mengembalikan nilai default untuk tipe referensi, yaitu null. Runtime akan mencoba untuk membuka kotak nilai kembali dengan memanggil intValuemetode di atasnya sebelum meneruskannya doStuff, dan pengecualian dilemparkan.

Lii
sumber
Saya terkejut setiap kali jawaban ini mendapat dukungan! Saya akan menduga bahwa pertanyaan itu tidak akan menarik banyak perhatian sejak Java 8, karena anymetode ini seharusnya hanya bekerja. Anda tidak mencari jawaban untuk hal-hal yang hanya berfungsi!
Lii
Saya datang ke sini karena saya tidak tahu mengapa kode saya tidak bekerja any()tetapi tidak apa-apa anyBoolean(), yang bagian terakhir dari jawaban Anda menjelaskan dengan indah.
AdrienW
274

Ini seharusnya bekerja

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;

verify(bar).DoStuff(any(Foo[].class));
naik opelet
sumber
31
kalau-kalau seseorang membutuhkannya di Scala:verify(bar).DoStuff(any[Array[Foo]])
tolitius
6
Saya punya masalah dengan impor, saya menggunakan any () dari hamcrest di impor saya dan bertabrakan dengan yang dari mockito.
Doppelganger
4
Silakan lihat API, argumen kelas hanya digunakan untuk casting, metode ini masih menerima objek apa pun! situs.mockito.org/mockito/docs/current/org/mockito/… . Gunakan isA () untuk case case ini situs.mockito.org/mockito/docs/current/org/mockito/… .
thilko
1
Kelas ini sekarang tidak digunakan lagi untuk menghindari bentrokan nama dengan Hamcrest. Gunakan org.mockito.ArgumentMatchers
leo9r
12

Anda dapat menggunakannya Mockito.isA()untuk itu:

import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.verify;

verify(bar).doStuff(isA(Foo[].class));

http://site.mockito.org/mockito/docs/current/org/mockito/Matchers.html#isA(java.lang.Class)

thilko
sumber
Ini jawaban yang benar. Menggunakan salah satu (Clazz) sepenuhnya salah.
Surasin Tancharoen
3
@SurasinTancharoen Sebenarnya, setiap (Kelas) hanyalah alias dari isA (Kelas) (lihat dokumen). Jadi sama sekali tidak salah.
jmiserez
8

Karena saya perlu menggunakan fitur ini untuk proyek terbaru saya (pada satu titik kami memperbarui dari 1.10.19), hanya agar pengguna (yang sudah menggunakan mockito-core versi 2.1.0 atau lebih tinggi ) tetap up to date, statis metode dari jawaban di atas harus diambil dari ArgumentMatcherskelas:

import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.ArgumentMatchers.any;

Ingatlah hal ini jika Anda berencana untuk memperbarui artefak Mockito Anda mulai dari versi 3, kelas ini mungkin tidak ada lagi:

Per 2.1.0 dan lebih tinggi, Javadoc dari org.mockito.Matchers menyatakan:

Gunakan org.mockito.ArgumentMatchers. Kelas ini sekarang tidak digunakan lagi untuk menghindari bentrokan nama dengan org.hamcrest.Matchers kelas Hamcrest * . Kelas ini kemungkinan akan dihapus dalam versi 3.0.

Saya telah menulis sedikit artikel tentang wildcard mockito jika Anda siap untuk membaca lebih lanjut.

Maciej Kowalski
sumber
Bagaimana saya bisa mengimpor org.mockito.ArgumentMatcher di Scala? Saya mencoba mengimpor org.mockito.ArgumentMatcher.any Saya mendapatkan nilai kesalahan `tidak ada anggota objek org.mockito.ArgumentMatcher
Manu Chadha
Bisakah Anda memberi tahu saya apa yang setara di versi 3.0?
Manu Chadha
Kita akan tahu begitu itu akan dirilis;)
Maciej Kowalski