Saya seorang pemula untuk pengembangan dan ke unit test pada khususnya. Saya kira kebutuhan saya cukup sederhana, tetapi saya ingin tahu pendapat orang lain tentang ini.
Misalkan saya memiliki dua kelas seperti itu -
public class First {
Second second ;
public First(){
second = new Second();
}
public String doSecond(){
return second.doSecond();
}
}
class Second {
public String doSecond(){
return "Do Something";
}
}
Katakanlah saya sedang menulis unit test untuk menguji First.doSecond()
metode. Namun, misalkan, saya ingin Second.doSecond()
kelas Mock seperti itu. Saya menggunakan Mockito untuk melakukan ini.
public void testFirst(){
Second sec = mock(Second.class);
when(sec.doSecond()).thenReturn("Stubbed Second");
First first = new First();
assertEquals("Stubbed Second", first.doSecond());
}
Saya melihat bahwa ejekan itu tidak berpengaruh dan pernyataan itu gagal. Apakah tidak ada cara untuk mengejek variabel anggota kelas yang ingin saya uji. ?
Ini tidak mungkin jika Anda tidak dapat mengubah kode Anda. Tapi saya suka injeksi ketergantungan dan Mockito mendukungnya:
Tes Anda:
Ini sangat bagus dan mudah.
sumber
Jika Anda melihat dengan cermat kode Anda, Anda akan melihat bahwa
second
properti dalam pengujian Anda masih merupakan contohSecond
, bukan tiruan (Anda tidak meneruskan tiruan kefirst
dalam kode Anda).Cara paling sederhana adalah membuat setter untuk
second
diFirst
kelas dan memberikannya mock secara eksplisit.Seperti ini:
Lain akan lulus
Second
contoh sebagaiFirst
parameter konstruktor.Jika Anda tidak dapat mengubah kode, saya pikir satu-satunya pilihan adalah menggunakan refleksi:
Tapi Anda mungkin bisa, karena jarang melakukan tes pada kode yang tidak Anda kontrol (walaupun orang dapat membayangkan skenario di mana Anda harus menguji perpustakaan eksternal karena penulisnya tidak :))
sumber
@Mock
dan anotasi Pertama dengan@InjectMocks
dan instantiasi Pertama di penginisialisasi. Mockito akan secara otomatis melakukan yang terbaik untuk menemukan tempat untuk menyuntikkan mock Kedua ke instance Pertama, termasuk pengaturan bidang pribadi yang cocok dengan tipe.@Mock
sekitar 1,5 (mungkin lebih awal, saya tidak yakin). 1.8.3 diperkenalkan@InjectMocks
juga@Spy
dan@Captor
.Jika Anda tidak dapat mengubah variabel anggota, maka cara lain untuk melakukannya adalah menggunakan powerMockit dan menelepon
Sekarang masalahnya adalah bahwa panggilan APAPUN ke Second baru akan mengembalikan contoh yang sama mengejek. Tetapi dalam kasus sederhana Anda ini akan berhasil.
sumber
Saya memiliki masalah yang sama di mana nilai pribadi tidak ditetapkan karena Mockito tidak memanggil konstruktor super. Inilah cara saya menambah ejekan dengan refleksi.
Pertama, saya membuat kelas TestUtils yang berisi banyak utilitas bermanfaat termasuk metode refleksi ini. Akses refleksi agak sulit untuk diterapkan setiap kali. Saya membuat metode ini untuk menguji kode pada proyek yang, karena satu dan lain alasan, tidak memiliki paket mengejek dan saya tidak diundang untuk memasukkannya.
Maka saya bisa menguji kelas dengan variabel pribadi seperti ini. Ini berguna untuk mengejek jauh di dalam pohon kelas yang tidak dapat Anda kendalikan.
Saya memodifikasi kode saya dari proyek saya yang sebenarnya di sini, di halaman. Mungkin ada satu atau dua masalah kompilasi. Saya pikir Anda mendapatkan ide umum. Jangan ragu untuk mengambil kode dan menggunakannya jika Anda merasa berguna.
sumber
Banyak orang lain telah menyarankan Anda untuk memikirkan kembali kode Anda untuk membuatnya lebih dapat diuji - saran yang bagus dan biasanya lebih sederhana daripada yang saya sarankan.
Jika Anda tidak dapat mengubah kode untuk membuatnya lebih dapat diuji, PowerMock: https://code.google.com/p/powermock/
PowerMock memperluas Mockito (jadi Anda tidak perlu mempelajari kerangka kerja mock baru), menyediakan fungsionalitas tambahan. Ini termasuk kemampuan untuk memiliki konstruktor mengembalikan tiruan. Kuat, tetapi sedikit rumit - jadi gunakan dengan bijak.
Anda menggunakan pelari Mock yang berbeda. Dan Anda perlu menyiapkan kelas yang akan memanggil konstruktor. (Perhatikan bahwa ini adalah gotcha yang umum - persiapkan kelas yang memanggil konstruktor, bukan kelas yang dibangun)
Kemudian dalam set-up pengujian Anda, Anda bisa menggunakan metode whenNew untuk membuat konstruktor mengembalikan tiruan
sumber
Ya, ini bisa dilakukan, seperti yang ditunjukkan tes berikut (ditulis dengan JMockit mocking API, yang saya kembangkan):
Namun, dengan Mockito, ujian semacam itu tidak dapat ditulis. Ini karena cara mengejek diimplementasikan di Mockito, di mana subclass dari kelas yang akan diejek dibuat; hanya instance dari subclass "mock" ini yang dapat memiliki perilaku mengejek, jadi Anda perlu meminta kode yang diuji menggunakannya alih-alih instance lainnya.
sumber
Jika Anda menginginkan alternatif untuk ReflectionTestUtils dari Spring di mockito, gunakan
sumber