Saya memiliki kelas terakhir, sesuatu seperti ini:
public final class RainOnTrees{
public void startRain(){
// some code here
}
}
Saya menggunakan kelas ini di beberapa kelas lain seperti ini:
public class Seasons{
RainOnTrees rain = new RainOnTrees();
public void findSeasonAndRain(){
rain.startRain();
}
}
dan di kelas tes JUnit saya karena Seasons.java
saya ingin mengejek RainOnTrees
kelas. Bagaimana saya bisa melakukan ini dengan Mockito?
Jawaban:
Mengejek final / kelas statis / metode hanya dimungkinkan dengan Mockito v2.
tambahkan ini dalam file gradle Anda:
Ini tidak mungkin dengan Mockito v1, dari FAQ Mockito :
sumber
Mockito 2 sekarang mendukung kelas dan metode akhir !
Tetapi untuk sekarang itu fitur "inkubasi". Dibutuhkan beberapa langkah untuk mengaktifkannya yang dijelaskan dalam What's New in Mockito 2 :
sumber
org.mockito.plugins.MockMaker
file di folder yang benar.Anda tidak dapat mengejek kelas terakhir dengan Mockito, karena Anda tidak dapat melakukannya sendiri.
Apa yang saya lakukan, adalah membuat kelas non-final untuk membungkus kelas akhir dan digunakan sebagai delegasi. Contoh dari ini adalah
TwitterFactory
kelas, dan ini adalah kelas saya yang bisa dipermainkan:Kerugiannya adalah ada banyak kode boilerplate; keuntungannya adalah Anda dapat menambahkan beberapa metode yang mungkin terkait dengan bisnis aplikasi Anda (seperti getInstance yang mengambil pengguna alih-alih accessToken, dalam kasus di atas).
Dalam kasus Anda, saya akan membuat kelas non-final
RainOnTrees
yang mendelegasikan ke kelas akhir. Atau, jika Anda bisa membuatnya non-final, itu akan lebih baik.sumber
@Delegate
untuk menangani banyak pelat ketel.tambahkan ini dalam file gradle Anda:
ini adalah konfigurasi untuk membuat mockito berfungsi dengan kelas akhir
sumber
org.mockito.exceptions.base.MockitoInitializationException: Could not initialize inline Byte Buddy mock maker. (This mock maker is not supported on Android.)
Gunakan Powermock. Tautan ini menunjukkan, bagaimana melakukannya: https://github.com/jayway/powermock/wiki/MockFinal
sumber
Powermock
untuk mengejek kelas akhir dan metode statis untuk meningkatkan cakupan saya yang secara resmi diperiksaSonarqube
. Cakupan adalah 0% sejak SonarQube, untuk alasan apa pun tidak mengenali kelas yang menggunakan Powermock di mana pun di dalamnya. Saya membawa saya dan tim saya beberapa waktu untuk menyadarinya dari beberapa utas online. Jadi itu hanyalah salah satu alasan untuk berhati-hati dengan Powermock dan mungkin tidak menggunakannya.Hanya untuk menindaklanjuti. Silakan tambahkan baris ini ke file gradle Anda:
Saya sudah mencoba berbagai versi mockito-core dan mockito-all. Tak satu pun dari mereka bekerja.
sumber
Saya kira Anda membuatnya
final
karena Anda ingin mencegah kelas lain dari perluasanRainOnTrees
. Seperti yang disarankan oleh Java Efektif (item 15), ada cara lain untuk menjaga kelas tetap dekat dengan ekstensi tanpa membuatnyafinal
:Hapus
final
kata kunci;Buat konstruktornya
private
. Tidak ada kelas yang dapat memperpanjangnya karena tidak akan dapat memanggilsuper
konstruktor;Buat metode pabrik statis untuk membuat instance kelas Anda.
Dengan menggunakan strategi ini, Anda akan dapat menggunakan Mockito dan menutup kelas Anda untuk ekstensi dengan sedikit kode boilerplate.
sumber
Saya memiliki masalah yang sama. Karena kelas yang saya coba mengejek adalah kelas yang sederhana, saya hanya membuat instance dan mengembalikannya.
sumber
Cobalah ini:
Ini berhasil untuk saya. "SomeMockableType.class" adalah kelas induk dari apa yang Anda ingin tiru atau mata-mata, dan beberapaInstanceThatIsNotMockableOrSpyable adalah kelas aktual yang Anda ingin tiru atau mata-mata.
Untuk lebih jelasnya lihat di sini
sumber
Solusi lain, yang mungkin berlaku dalam beberapa kasus, adalah membuat antarmuka yang diimplementasikan oleh kelas akhir itu, mengubah kode untuk menggunakan antarmuka, bukan kelas beton dan kemudian mengejek antarmuka. Ini memungkinkan Anda memisahkan kontrak (antarmuka) dari implementasi (kelas akhir). Tentu saja, jika yang Anda inginkan benar-benar mengikat ke kelas akhir, ini tidak akan berlaku.
sumber
Sebenarnya ada satu cara, yang saya gunakan untuk memata-matai. Ini akan bekerja untuk Anda hanya jika dua prasyarat dipenuhi:
Harap ingat Butir 16 dari Java Efektif . Anda dapat membuat pembungkus (bukan final) dan meneruskan semua panggilan ke turunan dari kelas akhir:
Sekarang Anda tidak hanya dapat mengejek kelas akhir Anda tetapi juga memata-matai:
sumber
Di Mockito 3 dan lebih banyak lagi saya memiliki masalah yang sama dan memperbaikinya dari tautan ini
Mock Kelas Akhir dan Metode dengan Mockito sebagai berikut
sumber
Penghemat waktu untuk orang-orang yang menghadapi masalah yang sama (Mockito + Kelas Akhir) di Android + Kotlin. Seperti dalam kelas Kotlin adalah final secara default. Saya menemukan solusi di salah satu sampel Android Google dengan komponen Arsitektur. Solusi dipilih dari sini: https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample
Buat anotasi berikut:
Ubah file gradle Anda. Ambil contoh dari sini: https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample/app/build.gradle
Sekarang Anda dapat membuat anotasi kelas apa saja untuk membuatnya terbuka untuk pengujian:
sumber
Ini dapat dilakukan jika Anda menggunakan Mockito2, dengan fitur inkubasi baru yang mendukung mengejek kelas akhir & metode.
Poin-poin penting yang perlu diperhatikan:
1. Buat file sederhana dengan nama "org.mockito.plugins.MockMaker" dan letakkan di folder bernama "mockito-extensions". Folder ini harus tersedia di classpath.
2. Konten file yang dibuat di atas harus satu baris seperti yang diberikan di bawah ini:
mock-maker-inline
Dua langkah di atas diperlukan untuk mengaktifkan mekanisme ekstensi mockito dan menggunakan fitur opt-in ini.
Kelas sampel adalah sebagai berikut: -
FinalClass.java
}
Foo.java
}
FooTest.java
}
Semoga ini bisa membantu.
Artikel lengkap hadir di sini mengejek-unmockable .
sumber
Ya masalah yang sama di sini, kita tidak bisa mengejek kelas terakhir dengan Mockito. Agar akurat, Mockito tidak dapat mengejek / memata-matai berikut:
Tetapi menggunakan kelas pembungkus menurut saya harga yang harus dibayar, jadi dapatkan PowerMockito sebagai gantinya.
sumber
Saya pikir Anda perlu berpikir lebih pada prinsipnya. Sebagai gantinya Anda kelas akhir menggunakan antarmuka dan antarmuka tiruan sebagai gantinya.
Untuk ini:
Menambahkan
dan mengejek antarmuka Anda:
sumber
Silakan lihat JMockit . Ini memiliki dokumentasi yang luas dengan banyak contoh. Di sini Anda memiliki contoh solusi dari masalah Anda (untuk menyederhanakan saya telah menambahkan konstruktor
Seasons
untuk menyuntikkanRainOnTrees
contoh mocked ):sumber
Solusi yang diberikan oleh RC dan Luigi R. Viggiano bersama mungkin adalah ide terbaik.
Meskipun Mockito tidak bisa , dengan desain, mengejek kelas akhir, pendekatan delegasi dimungkinkan . Ini memiliki kelebihan:
Dalam kasus pengujian Anda, Anda dengan sengaja meneruskan panggilan ke sistem yang sedang diuji. Karenanya, secara desain, dekorasi Anda tidak melakukan apa-apa.
Karenanya, Anda menguji juga dapat menunjukkan bahwa pengguna hanya dapat menghias API alih-alih memperpanjangnya.
Pada catatan yang lebih subyektif: Saya lebih suka menjaga kerangka kerja seminimal mungkin, itulah sebabnya JUnit dan Mockito biasanya cukup untuk saya. Bahkan, dengan membatasi cara ini kadang-kadang memaksa saya untuk refactor untuk selamanya juga.
sumber
Jika Anda mencoba menjalankan unit-test di bawah folder tes , solusi teratas baik-baik saja. Cukup ikuti itu menambahkan ekstensi.
Tetapi jika Anda ingin menjalankannya dengan kelas terkait Android seperti konteks atau aktivitas yang berada di bawah folder androidtest , jawabannya adalah untuk Anda.
sumber
Tambahkan dependensi ini untuk menjalankan mockito dengan sukses:
testImplementation 'org.mockito: mockito-core: 2.24.5'
testImplementation "org.mockito: mockito-inline: 2.24.5"
sumber
Seperti yang telah dinyatakan orang lain, ini tidak akan berhasil dengan Mockito. Saya akan menyarankan menggunakan refleksi untuk mengatur bidang spesifik pada objek yang sedang digunakan oleh kode yang diuji. Jika Anda sering melakukan hal ini, Anda dapat membungkus fungsi ini di perpustakaan.
Sebagai tambahan, jika Anda adalah satu-satunya yang menandai kelas final, berhentilah melakukannya. Saya mengalami pertanyaan ini karena saya bekerja dengan API di mana semuanya ditandai sebagai final untuk mencegah kebutuhan sah saya untuk ekstensi (mengejek), dan saya berharap bahwa pengembang tidak berasumsi bahwa saya tidak akan pernah perlu memperluas kelas.
sumber
final
harus menjadi default.Bagi kami, itu karena kami mengecualikan mockito-inline dari koin-test. Satu modul gradle sebenarnya membutuhkan ini dan karena alasan hanya gagal pada rilis build (debug build di IDE berfungsi) :-P
sumber
Untuk kelas akhir, tambahkan di bawah ini untuk mengejek dan memanggil statis atau non-statis.
1- tambahkan ini di tingkat kelas @SuppressStatucInitializationFor (value = {nama kelas dengan paket})
2- PowerMockito.mockStatic (classname.class) akan mengolok-olok kelas
3- lalu gunakan pernyataan when Anda untuk mengembalikan objek tiruan saat memanggil metode kelas ini.
Nikmati
sumber
Tidak mencoba final, tetapi untuk pribadi, menggunakan refleksi menghapus pengubah bekerja! sudah diperiksa lebih lanjut, tidak berfungsi untuk final.
sumber