Mengapa Mockito tidak mengejek metode statis?

267

Saya membaca beberapa utas di sini tentang metode statis, dan saya pikir saya mengerti masalah penyalahgunaan / penggunaan berlebihan metode statis dapat menyebabkan. Tetapi saya tidak benar-benar memahami mengapa sulit untuk mengejek metode statis.

Saya tahu kerangka mengejek lainnya, seperti PowerMock, bisa melakukan itu tetapi mengapa tidak bisa Mockito?

Saya membaca artikel ini , tetapi penulis tampaknya religius menentang kata itu static, mungkin itu pemahaman saya yang buruk.

Penjelasan / tautan yang mudah akan sangat bagus.

Abidi
sumber
12
Hanya catatan tambahan: PowerMock bukan perpustakaan objek tiruan per-se, itu hanya menambahkan fitur-fitur (mengejek statika dan agen) di atas perpustakaan lain. Kami menggunakan PowerMock + Mockito di tempat kerja mereka mengapung satu sama lain dengan baik.
Matthias

Jawaban:

238

Saya pikir alasannya mungkin bahwa perpustakaan objek tiruan biasanya membuat tiruan dengan secara dinamis membuat kelas saat runtime (menggunakan cglib ). Ini berarti mereka mengimplementasikan antarmuka saat runtime (itulah yang EasyMock lakukan jika saya tidak salah), atau mereka mewarisi dari kelas untuk mengejek (itulah yang dilakukan Mockito jika saya tidak salah). Kedua pendekatan tidak berfungsi untuk anggota statis, karena Anda tidak dapat menimpanya menggunakan pewarisan.

Satu-satunya cara untuk mengejek statika adalah dengan memodifikasi kode byte kelas pada saat runtime, yang saya kira sedikit lebih terlibat daripada pewarisan.

Itu dugaan saya, untuk apa nilainya ...

Matthias
sumber
7
Hal yang sama berlaku untuk mengejek konstruktor. Itu juga tidak bisa diubah melalui warisan.
Matthias
11
Mungkin juga patut ditambahkan bahwa beberapa pendukung TDD / TBD menganggap kurangnya metode statis dan mengejek konstruktor sebagai hal yang baik . Mereka berpendapat bahwa ketika Anda harus mengejek metode atau konstruktor statis, maka ini adalah indikator untuk desain kelas yang buruk. Misalnya, ketika mengikuti pendekatan IOC murni dalam merakit modul kode Anda, Anda bahkan tidak akan pernah perlu mengejek statika atau agen di tempat pertama (kecuali mereka adalah bagian dari beberapa komponen kotak hitam tentu saja). Lihat juga giorgiosironi.blogspot.com/2009/11/...
Matthias
200
Saya pikir alat mengejek harus memberi Anda apa yang Anda butuhkan tanpa berasumsi mereka tahu apa yang lebih baik untuk Anda. Misalnya, jika saya menggunakan pustaka pihak ketiga yang menggunakan pemanggilan metode statis yang saya perlu tiruan, alangkah baiknya bisa melakukannya. Gagasan bahwa kerangka kerja tiruan tidak akan memberi Anda beberapa kemampuan karena dipandang sebagai desain yang buruk pada dasarnya cacat.
Lo-Tan
11
@ Lo-Tan - itu seperti mengatakan bahwa bahasa harus mampu melakukan segalanya, tidak menganggapnya lebih baik dari Anda. Itu hanya kesombongan di pihak Anda, karena mereka dianggap mengesankan. Masalahnya di sini adalah bahwa pertempuran "anti / pro statis" tidak jelas, dan begitu pula kerangka kerjanya. Saya setuju bahwa kita harus memiliki keduanya. Tapi di mana fakta-fakta yang jelas, saya lebih memilih kerangka yang memaksakan fakta-fakta. Itu salah satu cara belajar - alat membuat Anda tetap pada jalurnya. Jadi Anda sendiri tidak perlu melakukannya. Tapi sekarang setiap kepala mie bisa memaksakan apa yang disebut "desain yang bagus". "Secara mendasar cacat" ...
nevvermind
13
@nevvermind Eh? Bahasa tingkat tinggi dimaksudkan untuk membantu Anda dan memiliki abstraksi yang diperlukan sehingga Anda dapat fokus pada bagian-bagian penting. Pustaka pengujian adalah alat - alat yang saya gunakan untuk menghasilkan kualitas yang lebih baik, dan semoga dirancang dengan lebih baik, kode. Apa gunanya perpustakaan pengujian / tiruan ketika memiliki keterbatasan yang mungkin berarti saya tidak dapat menggunakannya ketika saya harus mengintegrasikan kode yang dirancang dengan buruk oleh orang lain? Tampaknya tidak dipikirkan dengan baik, padahal, bahasa yang baik telah .
Lo-Tan
28

Jika Anda perlu mengejek metode statis, itu adalah indikator kuat untuk desain yang buruk. Biasanya, Anda mengejek ketergantungan ujian kelas Anda. Jika class-under-test Anda merujuk pada metode statis - seperti java.util.Math # sin misalnya - itu berarti kelas-under-test membutuhkan implementasi ini (misalnya akurasi vs kecepatan). Jika Anda ingin abstrak dari implementasi sinus konkret Anda mungkin perlu Interface (Anda melihat di mana ini akan)?

Jan
sumber
3
Yah, saya menggunakan metode statis untuk memberikan abstraksi tingkat tinggi, seperti "fasad kegigihan statis". Fasad seperti itu menjauhkan kode klien dari kerumitan dan perincian tingkat rendah dari API ORM, memberikan API yang lebih konsisten dan mudah digunakan, sambil memungkinkan banyak fleksibilitas.
Rogério
Dan mengapa Anda harus mengejeknya? Jika Anda bergantung pada metode statis, Anda "unit" atau "modul" bukan hanya kelas tetapi juga termasuk "fasad kegigihan statis".
Jan
88
Benar, tetapi kadang-kadang Anda mungkin tidak punya pilihan jika misalnya Anda perlu mengejek metode statis yang ada di beberapa kelas pihak ketiga.
Stijn Geukens
6
Benar, tetapi kadang-kadang kita mungkin berurusan dengan lajang.
Manu Manjunath
Satu-satunya pemikiran yang tidak dapat diselesaikan dengan abstrak adalah terlalu banyak level abstraksi ... Menambahkan lapisan abstraksi menambah kompleksitas, dan seringkali tidak perlu. Saya memikirkan contoh-contoh yang pernah saya lihat tentang kerangka kerja yang mencoba mengejek System.currentTimeMillis () dengan membungkus panggilan sederhana ini ke dalam satu kelas. Kami berakhir dengan kelas tunggal per metode alih-alih hanya memiliki metode - hanya untuk memfasilitasi pengujian. Dan kemudian ketika Anda memperkenalkan dep pihak ke-3 yang memanggil metode statis langsung alih-alih melalui pembungkus tunggal Anda, tes tetap gagal ...
Pater Jeremy Krieg
5

Saya sungguh-sungguh berpikir bahwa itu adalah kode bau jika Anda perlu mengejek metode statis juga.

  • Metode statis untuk mengakses fungsi umum? -> Gunakan contoh tunggal dan suntikkan itu
  • Kode pihak ketiga? -> Bungkus ke antarmuka / delegasi Anda sendiri (dan jika perlu jadikan singleton juga)

Satu-satunya saat ini tampaknya berlebihan bagi saya, adalah libs seperti Guava, tetapi Anda tidak perlu mengejek jenis ini karena itu bagian dari logika ... (hal-hal seperti Iterables.transform (..))
Dengan cara itu kode Anda sendiri tetap bersih, Anda dapat mengejek semua dependensi Anda dengan cara yang bersih, dan Anda memiliki lapisan anti korupsi terhadap dependensi eksternal. Saya telah melihat PowerMock dalam praktiknya dan semua kelas yang kami butuhkan dirancang dengan buruk. Integrasi PowerMock juga terkadang menyebabkan masalah serius
(mis. Https://code.google.com/p/powermock/issues/detail?id=355 )

PS: Sama berlaku untuk metode pribadi juga. Saya tidak berpikir tes harus tahu tentang detail metode pribadi. Jika sebuah kelas sangat kompleks sehingga tergoda untuk mengolok-olok metode pribadi, itu mungkin tanda untuk memecah kelas itu ...

pete83
sumber
2
Singleton akan membuat Anda menghadapi segala macam masalah, terutama ketika Anda menyadari bahwa Anda sebenarnya membutuhkan lebih dari satu contoh dan sekarang Anda perlu memperbaiki seluruh sistem Anda untuk mewujudkannya.
Ricardo Freitas
Saya tidak mengatakan, bahwa saya merekomendasikan Pola Singleton untuk semua orang. Yang saya maksud adalah, jika saya harus memutuskan antara kelas utilitas statis dan Singleton yang menawarkan fungsi yang sama, saya akan memilih Singleton. Dan jika sebuah kelas adalah Singleton atau tidak seharusnya dikontrol oleh kerangka kerja DI, di kelas saya @Inject SomeDependencydan dalam konfigurasi saya, saya mendefinisikan bind(SomeDependency.class).in(Singleton.class). Jadi jika besok bukan Singleton lagi, saya mengubah satu konfigurasi dan hanya itu.
pete83
@ pete83 aku mendengarmu, saudara. Namun saya memiliki masalah dengan lib pengujian atau kerangka kerja yang membutuhkan devs untuk mengubah desain mereka untuk memenuhi desain / batas kerangka uji. Itu adalah IMO meletakkan kereta di depan kuda, atau ekor mengibas-ngibaskan anjing.
Matt Campbell
1
Argumen itu tidak masuk akal bagi saya. Pola Singleton telah tidak disukai selama bertahun-tahun sekarang, karena terlalu banyak alasan untuk disebutkan di sini. Apa yang dimaksud dengan kode "bersih"? Jika saya memiliki metode instance kelas yang memanggil metode pembantu statis yang mengembalikan beberapa operasi I / O, mengapa saya tidak ingin itu diejek dalam sebuah tes? Dan bagaimana desain yang buruk itu? Semua metode statis mengejek yang mengelilinginya ini tidak cocok. Mengejek suatu metode adalah kebalikan dari mengujinya. Jika terlalu sulit untuk diterapkan maka katakan saja dan lakukan saja
eggmatters
Oh man, aku tidak pernah berbicara tentang pola Singleton sekolah tua di mana semua orang menelepon ke Foo.getInstance()mana-mana. Saya hanya menulis singleton dalam jawaban untuk melawan argumen "tetapi metode statis tidak memerlukan penciptaan banyak objek pembungkus". Juga secara konsep bagi saya ada sedikit perbedaan antara metode statis dan metode contoh pada singleton, hanya saja Anda tidak dapat mengejek kolaborator singleton ini. Tapi singleton atau bukan sama sekali bukan poin yang saya coba buat, intinya adalah menyuntikkan dan mengejek kolaborator dan tidak memanggil metode statis jika itu membuat pengujian sulit.
pete83
4

Mockito mengembalikan objek tetapi statis berarti "level kelas, bukan level objek" Jadi mockito akan memberikan pengecualian pointer nol untuk statis.

salsinga
sumber
0

Dalam beberapa kasus, metode statis bisa sulit untuk diuji, terutama jika mereka perlu diejek, itulah sebabnya sebagian besar kerangka kerja mengejek tidak mendukungnya. Saya menemukan posting blog ini sangat berguna dalam menentukan bagaimana cara mengejek metode dan kelas statis.

Tyler Treat
sumber
1
Mengolok-olok metode statis bahkan lebih mudah daripada mengolok-olok metode contoh (karena tidak ada contoh), ketika menggunakan API mengejek yang sesuai.
Rogério
Ini seperti menjawab pertanyaan dengan pertanyaan itu sendiri, yang mengapa sulit untuk melakukannya, yang mana ini bukan jawaban.
Matthias
40
Saya downvoted karena posting blog merekomendasikan solusi yang mahal (refactoring kode produksi), daripada benar-benar memecahkan masalah mengisolasi kelas dari metode statis yang kebetulan digunakan. IMO, alat mengejek yang benar-benar melakukan pekerjaan tidak akan mendiskriminasi metode apa pun; seorang pengembang harus bebas untuk memutuskan apakah penggunaan metode statis baik atau buruk dalam situasi tertentu, daripada dipaksa turun satu jalur.
Rogério