Apakah ada cara, menggunakan Mockito, untuk mengejek beberapa metode di kelas, tetapi tidak yang lain?
Sebagai contoh, dalam kelas ini (diakui dibuat-buat) Stock
saya ingin mengejek getPrice()
dan getQuantity()
mengembalikan nilai (seperti yang ditunjukkan dalam cuplikan tes di bawah) tetapi saya ingin getValue()
melakukan penggandaan seperti yang dikodekan di Stock
kelas.
public class Stock {
private final double price;
private final int quantity;
Stock(double price, int quantity) {
this.price = price;
this.quantity = quantity;
}
public double getPrice() {
return price;
}
public int getQuantity() {
return quantity;
}
public double getValue() {
return getPrice() * getQuantity();
}
@Test
public void getValueTest() {
Stock stock = mock(Stock.class);
when(stock.getPrice()).thenReturn(100.00);
when(stock.getQuantity()).thenReturn(200);
double value = stock.getValue();
// Unfortunately the following assert fails, because the mock Stock getValue() method does not perform the Stock.getValue() calculation code.
assertEquals("Stock value not correct", 100.00*200, value, .00001);
}
Jawaban:
Untuk langsung menjawab pertanyaan Anda, ya, Anda dapat mengejek beberapa metode tanpa mengejek orang lain. Ini disebut tiruan parsial . Lihat dokumentasi Mockito pada tiruan parsial untuk informasi lebih lanjut.
Sebagai contoh Anda, Anda dapat melakukan sesuatu seperti berikut ini, dalam pengujian Anda:
Dalam hal ini, setiap implementasi metode diejek, kecuali ditentukan
thenCallRealMethod()
dalamwhen(..)
klausa.Ada juga kemungkinan sebaliknya dengan mata - mata bukannya tiruan :
Dalam hal itu, semua implementasi metode adalah yang asli, kecuali jika Anda telah mendefinisikan perilaku yang dipermainkan
when(..)
.Ada satu perangkap penting ketika Anda menggunakan
when(Object)
dengan mata-mata seperti pada contoh sebelumnya. Metode nyata akan dipanggil (karenastock.getPrice()
dievaluasi sebelumwhen(..)
saat runtime). Ini bisa menjadi masalah jika metode Anda mengandung logika yang tidak boleh dipanggil. Anda dapat menulis contoh sebelumnya seperti ini:Kemungkinan lain mungkin untuk digunakan
org.mockito.Mockito.CALLS_REAL_METHODS
, seperti:Delegasi ini membatalkan panggilan untuk implementasi nyata.
Namun, dengan contoh Anda, saya percaya itu masih akan gagal, karena implementasi
getValue()
bergantung padaquantity
danprice
, bukangetQuantity()
dangetPrice()
, yang merupakan apa yang telah Anda cemooh.Kemungkinan lain adalah untuk menghindari cemoohan sama sekali:
sumber
Stock stock = spy(Stock.class);
Ini tampaknya salah,spy
metode tampaknya hanya menerima objek bukan kelas.doReturn(retval).when(spyObj).methodName(args)
danwhen(spyObj.methodName(args)).thenReturn(retval)
Mengejek sebagian kelas juga didukung melalui Spy di mockito
Periksa
1.10.19
dan2.7.22
dokumentasi untuk penjelasan terperinci.sumber
Menurut dokumen :
sumber
class NaughtyLinkedList extends LinkedList { public int size() { throw new RuntimeException("don't call me");} } @Test public void partialMockNaughtLinkedList(){ List mock = mock(NaughtyLinkedList.class, CALLS_REAL_METHODS); mock.add(new Object()); // this calls the real function when(mock.size()).thenReturn(2); // For whatever reason, this lines throws the RuntimeException. assertEquals(2,mock.size()); }
Ini tidak berhasil. Apa pun alasannya, ketika "kapan" dijalankan, sebenarnya mengeksekusi metode yang seharusnya diejek. Kode:Apa yang Anda inginkan
org.mockito.Mockito.CALLS_REAL_METHODS
sesuai dengan dokumen:Dengan demikian kode Anda akan terlihat seperti:
Panggilan ke
Stock stock = mock(Stock.class);
panggilanorg.mockito.Mockito.mock(Class<T>)
yang terlihat seperti ini:Dokumen nilai
RETURNS_DEFAULTS
memberi tahu:sumber
withSettings()...
seperti itu? Tampaknyaorg.mockito.internal.stubbing.answers.CallsRealMethods()
(misalnya) dapat melakukan pekerjaan ... dan javadoc untuk kelas ini secara khusus mengatakan itu untuk digunakan untuk mengolok-olok sebagian ...thenReturn
benar-benar akan menjalankan metode (yang mungkin menyebabkan masalah, meskipun tidak dalam contoh ini), dan lebihdoReturn
disukai dalam kasus seperti itu ...?Mengejek sebagian menggunakan metode mata-mata Mockito bisa menjadi solusi untuk masalah Anda, seperti yang sudah dinyatakan dalam jawaban di atas. Untuk tingkat tertentu saya setuju bahwa, untuk kasus penggunaan konkret Anda, mungkin lebih tepat untuk mengejek pencarian DB. Dari pengalaman saya ini tidak selalu mungkin - setidaknya tidak tanpa solusi lain - yang saya anggap sangat rumit atau setidaknya rapuh. Perhatikan, mengejek sebagian itu tidak berfungsi dengan versi sekutu Mockito. Anda telah menggunakan setidaknya 1.8.0.
Saya hanya akan menulis komentar sederhana untuk pertanyaan asli alih-alih memposting jawaban ini, tetapi StackOverflow tidak mengizinkan ini.
Hanya satu hal lagi: Saya benar-benar tidak dapat memahami bahwa beberapa kali pertanyaan diajukan di sini mendapat komentar dengan "Mengapa Anda ingin melakukan ini" tanpa setidaknya mencoba memahami masalahnya. Terutama ketika datang kemudian perlu untuk mengejek parsial benar-benar ada banyak kasus penggunaan yang bisa saya bayangkan di mana itu akan berguna. Itu sebabnya orang-orang dari Mockito menyediakan fungsi itu. Fitur ini tentu saja tidak boleh digunakan secara berlebihan. Tetapi ketika kita berbicara tentang pengaturan kasus uji yang tidak dapat dibuat dengan cara yang sangat rumit, mata-mata harus digunakan.
sumber