Saya punya beberapa metode yang harus memanggil System.exit()
input tertentu. Sayangnya, menguji kasus-kasus ini menyebabkan JUnit berakhir! Menempatkan panggilan metode di Thread baru tampaknya tidak membantu, karena System.exit()
mengakhiri JVM, bukan hanya utas saat ini. Apakah ada pola umum untuk menangani ini? Sebagai contoh, dapatkah saya menggantikan rintisan System.exit()
?
[EDIT] Kelas yang dimaksud sebenarnya adalah alat baris perintah yang saya coba uji di dalam JUnit. Mungkin JUnit bukan alat yang tepat untuk pekerjaan itu? Saran untuk alat pengujian regresi komplementer dipersilahkan (lebih disukai sesuatu yang terintegrasi dengan baik dengan JUnit dan EclEmma).
java
multithreading
unit-testing
junit
testability
Chris Conway
sumber
sumber
System.exit()
itu buruk - program Anda harus gagal dengan cepat. Melempar pengecualian hanya memperpanjang aplikasi dalam keadaan tidak valid dalam situasi di mana pengembang ingin keluar dan akan memberikan kesalahan palsu.Jawaban:
Memang, Derkeiler.com menyarankan:
System.exit()
?System.exit()
untuk benar-benar keluar dari JVM:Pembaruan Desember 2012:
Akan mengusulkan dalam komentar menggunakan Aturan Sistem , kumpulan aturan JUnit (4.9+) untuk menguji kode yang digunakan
java.lang.System
.Ini awalnya disebutkan oleh Stefan Birkner dalam jawabannya pada Desember 2011.
Misalnya:
sumber
System.exit
kapan saja argumen baris perintah yang tidak valid diberikan.Pustaka Aturan Sistem memiliki aturan JUnit yang disebut ExpectedSystemExit. Dengan aturan ini Anda dapat menguji kode, yang memanggil System.exit (...):
Pengungkapan penuh: Saya penulis perpustakaan itu.
sumber
ExpectedSystemRule
bagus, tentu saja; masalahnya adalah membutuhkan perpustakaan pihak ketiga tambahan yang menyediakan sangat sedikit dalam hal kegunaan dunia nyata, dan spesifik JUnit.exit.checkAssertionAfterwards()
.Bagaimana dengan menyuntikkan "ExitManager" ke dalam Metode ini:
Kode produksi menggunakan ExitManagerImpl dan kode tes menggunakan ExitManagerMock dan dapat memeriksa apakah exit () dipanggil dan dengan kode keluar mana.
sumber
Anda sebenarnya dapat mengejek atau mematikan
System.exit
metodenya, dalam tes JUnit.Misalnya, menggunakan JMockit Anda dapat menulis (ada juga cara lain):
EDIT: Tes alternatif (menggunakan JMockit API terbaru) yang tidak memungkinkan kode untuk dijalankan setelah panggilan ke
System.exit(n)
:sumber
exit
panggilan (bukan bahwa itu benar-benar masalah, IMO).Runtime
dapat diejek " dapat diejek, tetapi tidak berhentiSystem.exit
setidaknya dalam skenario saya menjalankan Tes di Gradle.Salah satu trik yang kami gunakan dalam basis kode kami adalah membuat panggilan ke System.exit () dienkapsulasi dalam imp Runnable, yang metode yang dimaksud digunakan secara default. Untuk pengujian unit, kami menetapkan Runnable tiruan yang berbeda. Sesuatu seperti ini:
... dan metode uji JUnit ...
sumber
Buat kelas mock-mampu yang membungkus System.exit ()
Saya setuju dengan EricSchaefer . Tetapi jika Anda menggunakan kerangka kerja mocking yang baik seperti Mockito kelas beton sederhana sudah cukup, tidak perlu untuk antarmuka dan dua implementasi.
Menghentikan eksekusi tes pada System.exit ()
Masalah:
Mocked
Sytem.exit()
tidak akan menghentikan eksekusi. Ini buruk jika Anda ingin menguji yangthing2
tidak dieksekusi.Larutan:
Anda harus memperbaiki kode ini seperti yang disarankan oleh martin :
Dan lakukan
System.exit(status)
dalam fungsi panggilan. Ini memaksa Anda untuk memiliki semua milik AndaSystem.exit()
di satu tempat di atau dekatmain()
. Ini lebih bersih daripada memanggilSystem.exit()
jauh ke dalam logika Anda.Kode
Pembungkus:
Utama:
Uji:
sumber
Saya suka beberapa jawaban yang sudah diberikan tetapi saya ingin menunjukkan teknik berbeda yang sering berguna ketika mendapatkan kode lama yang diuji. Kode yang diberikan seperti:
Anda dapat melakukan refactoring yang aman untuk membuat metode yang membungkus panggilan System.exit:
Kemudian Anda dapat membuat palsu untuk pengujian Anda yang menimpa keluar:
Ini adalah teknik generik untuk menggantikan perilaku untuk kasus uji, dan saya menggunakannya sepanjang waktu ketika refactoring kode lama. Biasanya tidak di mana saya akan meninggalkan sesuatu, tetapi langkah menengah untuk mendapatkan kode yang ada di bawah tes.
sumber
Pandangan cepat pada api, menunjukkan bahwa System.exit dapat melempar pengecualian esp. jika seorang manajer keamanan melarang penutupan vm. Mungkin solusinya adalah menginstal manajer seperti itu.
sumber
Anda dapat menggunakan java SecurityManager untuk mencegah utas saat ini dari mematikan Java VM. Kode berikut harus melakukan apa yang Anda inginkan:
sumber
Agar jawaban VonC berjalan pada JUnit 4, saya telah memodifikasi kodenya sebagai berikut
sumber
Anda dapat menguji System.exit (..) dengan mengganti instance Runtime. Misalnya dengan TestNG + Mockito:
sumber
Ada lingkungan di mana kode keluar yang dikembalikan digunakan oleh program panggilan (seperti ERRORLEVEL di MS Batch). Kami memiliki tes di sekitar metode utama yang melakukan ini dalam kode kami, dan pendekatan kami telah menggunakan penggantian SecurityManager yang sama seperti yang digunakan dalam tes lain di sini.
Tadi malam saya mengumpulkan JAR kecil menggunakan penjelasan Junit @Rule untuk menyembunyikan kode manajer keamanan, serta menambahkan harapan berdasarkan kode pengembalian yang diharapkan. http://code.google.com/p/junitsystemrules/
sumber
Sebagian besar solusi akan melakukannya
System.exit()
ini disebutSecurityManager
Dengan demikian, sebagian besar solusi tidak cocok untuk situasi di mana:
System.exit()
assertAll()
, misalnya.Saya tidak senang dengan pembatasan yang diberlakukan oleh solusi yang ada yang disajikan dalam jawaban lain, dan dengan demikian muncul dengan sesuatu sendiri.
Kelas berikut menyediakan metode
assertExits(int expectedStatus, Executable executable)
yang menyatakan bahwaSystem.exit()
dipanggil denganstatus
nilai yang ditentukan , dan tes dapat dilanjutkan setelahnya. Ini bekerja dengan cara yang sama seperti JUnit 5assertThrows
. Itu juga menghormati manajer keamanan yang ada.Ada satu masalah yang tersisa: Ketika kode yang diuji menginstal manajer keamanan baru yang sepenuhnya menggantikan manajer keamanan yang ditetapkan oleh tes. Semua
SecurityManager
solusi berbasis lainnya yang saya kenal menderita masalah yang sama.Anda dapat menggunakan kelas seperti ini:
Kode dapat dengan mudah porting ke JUnit 4, TestNG, atau kerangka kerja lainnya, jika perlu. Satu-satunya elemen kerangka spesifik gagal tes. Ini dapat dengan mudah diubah menjadi sesuatu yang independen kerangka kerja (selain Junit 4
Rule
Ada ruang untuk perbaikan, misalnya, kelebihan muatan
assertExits()
dengan pesan yang dapat disesuaikan.sumber
Gunakan
Runtime.exec(String command)
untuk memulai JVM dalam proses terpisah.sumber
Ada masalah kecil dengan
SecurityManager
solusinya. Beberapa metode, sepertiJFrame.exitOnClose
, juga meneleponSecurityManager.checkExit
. Dalam aplikasi saya, saya tidak ingin panggilan itu gagal, jadi saya gunakansumber
Memanggil System.exit () adalah praktik yang buruk, kecuali itu dilakukan di dalam main (). Metode-metode ini harus membuang pengecualian yang, pada akhirnya, ditangkap oleh main Anda (), yang kemudian memanggil System.exit dengan kode yang sesuai.
sumber