Bisakah Mockito mematikan metode tanpa memperhatikan argumen?

302

Saya mencoba menguji beberapa kode lama, menggunakan Mockito.

Saya ingin rintisan FooDaoyang digunakan dalam produksi sebagai berikut:

foo = fooDao.getBar(new Bazoo());

Saya bisa menulis:

when(fooDao.getBar(new Bazoo())).thenReturn(myFoo);

Tetapi masalah yang jelas adalah bahwa getBar()tidak pernah dipanggil dengan Bazooobjek yang sama yang saya matikan metode untuk. (Kutukan newoperator itu!)

Saya akan senang jika saya bisa mematikan metode dengan cara yang mengembalikan myFootanpa argumen. Gagal itu, saya akan mendengarkan saran solusi lainnya, tapi saya benar-benar ingin menghindari mengubah kode produksi sampai ada cakupan pengujian yang masuk akal.

Eric Wilson
sumber

Jawaban:

456
when(
  fooDao.getBar(
    any(Bazoo.class)
  )
).thenReturn(myFoo);

atau (untuk menghindari null):

when(
  fooDao.getBar(
    (Bazoo)notNull()
  )
).thenReturn(myFoo);

Jangan lupa untuk mengimpor pencocokan (banyak yang lain tersedia):

Untuk Mockito 2.1.0 dan yang lebih baru:

import static org.mockito.ArgumentMatchers.*;

Untuk versi yang lebih lama:

import static org.mockito.Matchers.*;
Tomasz Nurkiewicz
sumber
2
Saya suka ketika jawabannya mendahului akhir dari 'terima jawaban dibekukan'.
Eric Wilson
10
Ada yang notNull(Bazoo.class)seperti any(Bazoo.class)(mungkin tidak ada pada saat jawaban ini)
Dandre Allison
2
Saya memiliki situasi yang sedikit istimewa di mana saya dapat memiliki dua dari dua argumen yang mungkin - Bazooatau Cazooyang keduanya merupakan subkelas dari, katakanlah Azoo,. untuk Bazoosaya perlu kembali foo, tetapi untuk Cazoosaya perlu kembali bar. dalam situasi ini Matchers.any()solusi yang diusulkan tidak berhasil, namun Matchers.isA()bekerja dengan sempurna.
Tanvir
3
org.mockito.Matcherssekarang sudah ditinggalkan - org.mockito.ArgumentMatcherssebagai gantinya, yaitu import static org.mockito.ArgumentMatchers.*(lihat dokumen )
DontDivideByZero
when(myFoo.knowsWhatsUp()).thenReturn(myMoney);
6rchid
18

Gunakan seperti ini:

when(
  fooDao.getBar(
    Matchers.<Bazoo>any()
  )
).thenReturn(myFoo);

Sebelum Anda perlu mengimpor Mockito.Matchers

Hamad
sumber
1
Ini dirampas!
DrB
15

http://site.mockito.org/mockito/docs/1.10.19/org/mockito/Matchers.html

anyObject() harus sesuai dengan kebutuhan Anda.

Juga, Anda selalu dapat mempertimbangkan implementasi hashCode()dan equals()untuk Bazookelas. Ini akan membuat contoh kode Anda bekerja seperti yang Anda inginkan.

Buhb
sumber
Setuju dengan saran kedua, tetapi saya masih memilih untuk tidak melakukan itu karena alasan non-teknis.
Eric Wilson
1
Kelas Matchers sudah tidak digunakan lagi (lihat dokumen - "Kelas ini kemungkinan akan dihapus dalam versi 3.0" )
Johannes Rabauer
1

Pilihan lain adalah mengandalkan equalsmetode mode lama yang bagus . Selama argumen dalam whenmock equalsargumen dalam kode yang diuji, maka Mockito akan cocok dengan mock.

Berikut ini sebuah contoh.

public class MyPojo {

    public MyPojo( String someField ) {
        this.someField = someField;
    }

    private String someField;

    @Override
    public boolean equals( Object o ) {
        if ( this == o ) return true;
        if ( o == null || getClass() != o.getClass() ) return false;
        MyPojo myPojo = ( MyPojo ) o;
        return someField.equals( myPojo.someField );
    }

}

kemudian, dengan anggapan Anda tahu berapa nilainya someField, Anda dapat mengejeknya seperti ini.

when(fooDao.getBar(new MyPojo(expectedSomeField))).thenReturn(myFoo);

pro: Ini lebih eksplisit daripada anypencocokan. Sebagai peninjau kode, saya tetap membuka mata anydalam kode yang ditulis pengembang junior, karena melirik logika kode mereka untuk menghasilkan objek yang sesuai yang dilewatkan.

con: Terkadang bidang yang diteruskan ke objek adalah ID acak. Untuk kasus ini, Anda tidak dapat dengan mudah membuat objek argumen yang diharapkan dalam kode tiruan Anda.

Pendekatan lain yang mungkin adalah dengan menggunakan objek Mockito Answeryang dapat digunakan dengan whenmetode ini. Answermemungkinkan Anda mencegat panggilan aktual dan memeriksa argumen input dan mengembalikan objek tiruan. Dalam contoh di bawah ini saya menggunakan anyuntuk menangkap permintaan apa pun untuk metode yang diejek. Tapi kemudian di Answerlambda, saya dapat memeriksa argumen Bazo lebih lanjut ... mungkin untuk memverifikasi bahwa ID yang tepat diberikan padanya. Saya lebih suka ini daripada anydengan sendirinya sehingga setidaknya beberapa inspeksi dilakukan pada argumen.

    Bar mockBar = //generate mock Bar.

    when(fooDao.getBar(any(Bazo.class))
    .thenAnswer(  ( InvocationOnMock invocationOnMock) -> {
        Bazo actualBazo = invocationOnMock.getArgument( 0 );

        //inspect the actualBazo here and thrw exception if it does not meet your testing requirements.
        return mockBar;
    } );

Jadi untuk meringkas semuanya, saya suka mengandalkan equals(di mana argumen yang diharapkan dan argumen yang sebenarnya harus sama satu sama lain) dan jika persamaan tidak mungkin (karena tidak dapat memprediksi keadaan argumen yang sebenarnya), saya akan menggunakan untuk Answermemeriksa argumen.

Jose Martinez
sumber