Bagaimana saya bisa menggunakan JUnit4 secara idiomatis untuk menguji bahwa beberapa kode melempar pengecualian?
Sementara saya pasti bisa melakukan sesuatu seperti ini:
@Test
public void testFooThrowsIndexOutOfBoundsException() {
boolean thrown = false;
try {
foo.doStuff();
} catch (IndexOutOfBoundsException e) {
thrown = true;
}
assertTrue(thrown);
}
Saya ingat bahwa ada anotasi atau Assert.xyz atau sesuatu yang jauh lebih tidak suram dan jauh lebih dalam semangat JUnit untuk situasi semacam ini.
org.mockito.Mockito.verify
dengan berbagai parameter untuk memastikan bahwa hal-hal tertentu terjadi (sehingga layanan logger dipanggil dengan parameter yang benar) sebelum pengecualian dilemparkan.Jawaban:
Itu tergantung pada versi JUnit dan perpustakaan apa yang Anda gunakan.
Jawaban asli untuk
JUnit <= 4.12
adalah:Meskipun jawaban https://stackoverflow.com/a/31826781/2986984 memiliki lebih banyak opsi untuk JUnit <= 4.12.
Referensi:
sumber
ArrayList
meresponsget()
adalah tidak relevan. Jika saya memilih di masa depan untuk pindah ke array primitif, maka saya harus mengubah implementasi tes ini. Struktur data harus disembunyikan, sehingga tes dapat fokus pada perilaku kelas .Sunting: Sekarang JUnit 5 dan JUnit 4.13 telah dirilis, opsi terbaik adalah menggunakan
Assertions.assertThrows()
(untuk JUnit 5) danAssert.assertThrows()
(untuk JUnit 4.13). Lihat jawaban saya yang lain untuk detailnya.Jika Anda belum bermigrasi ke JUnit 5, tetapi dapat menggunakan JUnit 4.7, Anda dapat menggunakan
ExpectedException
Aturan:Ini jauh lebih baik daripada
@Test(expected=IndexOutOfBoundsException.class)
karena tes akan gagal jikaIndexOutOfBoundsException
dilemparkan sebelumnyafoo.doStuff()
Lihat artikel ini untuk detailnya
sumber
ExpectedException
kelas memiliki cara untuk mencocokkan pesan pengecualian, atau bahkan menulis pencocokan Anda sendiri yang tergantung pada kelas pengecualian. Kedua, Anda dapat mengatur ekspektasi Anda segera sebelum baris kode yang Anda harapkan untuk melemparkan pengecualian - yang berarti pengujian Anda akan gagal jika baris kode yang salah melemparkan pengecualian; sedangkan tidak ada cara untuk melakukan itu dengan solusi skaffman.Hati-hati menggunakan pengecualian yang diharapkan, karena hanya menegaskan bahwa metode melempar pengecualian itu, bukan baris kode tertentu dalam pengujian.
Saya cenderung menggunakan ini untuk menguji validasi parameter, karena metode seperti itu biasanya sangat sederhana, tetapi tes yang lebih kompleks mungkin lebih baik dilayani dengan:
Terapkan penilaian.
sumber
ExpectedException
, hal normal yang harus dilakukan adalah mengatur ekspektasi tepat sebelum garis yang Anda harapkan untuk melempar pengecualian. Dengan begitu, jika baris sebelumnya melempar pengecualian, itu tidak akan memicu aturan, dan tes akan gagal.Seperti yang dijawab sebelumnya, ada banyak cara untuk berurusan dengan pengecualian di JUnit. Tetapi dengan Java 8 ada satu lagi: menggunakan Ekspresi Lambda. Dengan Lambda Expressions, kami dapat mencapai sintaksis seperti ini:
assertThrown menerima antarmuka fungsional, yang instansinya dapat dibuat dengan ekspresi lambda, referensi metode, atau referensi konstruktor. assertThrown menerima bahwa antarmuka akan mengharapkan dan siap untuk menangani pengecualian.
Ini adalah teknik yang relatif sederhana namun kuat.
Lihatlah posting blog ini yang menjelaskan teknik ini: http://blog.codeleak.pl/2014/07/junit-testing-exception-with-java-8-and-lambda-expressions.html
Kode sumber dapat ditemukan di sini: https://github.com/kolorobot/unit-testing-demo/tree/master/src/test/java/com/github/kolorobot/exceptions/java8
Pengungkapan: Saya adalah penulis blog dan proyek.
sumber
new DummyService()::someMethod
adalah aMethodHandle
, tetapi pendekatan ini bekerja sama baiknya dengan ekspresi lambda.di junit, ada empat cara untuk menguji pengecualian.
junit5.x
untuk junit5.x, Anda dapat menggunakan
assertThrows
sebagai berikutjunit4.x
untuk junit4.x, gunakan atribut opsional 'diharapkan' dari Test annonation
untuk junit4.x, gunakan aturan ExpectedException
Anda juga dapat menggunakan cara coba / tangkap klasik yang banyak digunakan dalam kerangka kerja junit 3
begitu
untuk info lebih lanjut, Anda dapat membaca dokumen ini dan panduan pengguna junit5 untuk detailnya.
sumber
Trowable
ke metodeExpectedException.expect
. silakan lihat tanda tangan itu . @miusertl; dr
post-JDK8: Gunakan AssertJ atau custom lambdas untuk menegaskan perilaku yang luar biasa .
pra-JDK8: Saya akan merekomendasikan barang lama yang baik
try
-catch
blok. ( Jangan lupa untuk menambahkanfail()
pernyataan sebelumcatch
blok )Terlepas dari Junit 4 atau JUnit 5.
cerita panjang
Dimungkinkan untuk menulis sendiri, lakukan sendiri
try
-catch
blokir atau gunakan alat JUnit (@Test(expected = ...)
atau@Rule ExpectedException
fitur aturan JUnit).Tetapi cara-cara ini tidak begitu elegan dan tidak bisa dibaca dengan baik dengan alat lain. Selain itu, perkakas JUnit memang memiliki beberapa jebakan.
The
try
-catch
blok Anda harus menulis blok di sekitar perilaku diuji dan menulis pernyataan di blok catch, yang mungkin baik-baik saja tetapi banyak menemukan bahwa gaya ini interupsi aliran pembacaan tes. Juga, Anda perlu menulisAssert.fail
di akhirtry
blok. Jika tidak, tes dapat kehilangan satu sisi dari pernyataan; PMD , findbugs atau Sonar akan menemukan masalah seperti itu.The
@Test(expected = ...)
fitur menarik seperti yang Anda dapat menulis kode kurang dan kemudian menulis tes ini konon kurang rentan terhadap kesalahan coding. Tetapi pendekatan ini kurang di beberapa daerah.Juga karena harapan ditempatkan di sekitar dalam metode, tergantung pada bagaimana kode yang diuji ditulis maka bagian yang salah dari kode pengujian dapat membuang pengecualian, yang mengarah ke tes positif palsu dan saya tidak yakin bahwa PMD , findbugs atau Sonar akan memberikan petunjuk tentang kode tersebut.
The
ExpectedException
Aturan ini juga merupakan upaya untuk memperbaiki peringatan sebelumnya, tapi rasanya sedikit aneh untuk digunakan karena menggunakan gaya harapan, EasyMock pengguna tahu betul gaya ini. Mungkin cocok untuk beberapa orang, tetapi jika Anda mengikuti prinsip-prinsip Behavior Driven Development (BDD) atau Arrange Act Assert (AAA)ExpectedException
aturan tidak akan cocok dengan gaya penulisan mereka. Selain itu mungkin mengalami masalah yang sama seperti@Test
cara, tergantung di mana Anda menempatkan harapan.Bahkan pengecualian yang diharapkan ditempatkan sebelum pernyataan tes, itu merusak aliran bacaan Anda jika tes mengikuti BDD atau AAA.
Juga, lihat masalah komentar ini pada JUnit dari penulis
ExpectedException
. JUnit 4.13-beta-2 bahkan mencela mekanisme ini:Jadi opsi di atas memiliki semua muatan peringatan, dan jelas tidak kebal terhadap kesalahan pengkode.
Ada sebuah proyek yang saya sadari setelah membuat jawaban ini yang tampak menjanjikan, itu pengecualian .
Seperti yang dijelaskan dalam deskripsi proyek, itu memungkinkan seorang pembuat kode menulis dalam garis fasih kode menangkap pengecualian dan menawarkan pengecualian ini untuk pernyataan terakhir. Dan Anda dapat menggunakan perpustakaan pernyataan apa pun seperti Hamcrest atau AssertJ .
Contoh cepat diambil dari beranda:
Seperti yang Anda lihat kode ini benar-benar mudah, Anda menangkap pengecualian pada baris tertentu,
then
API adalah alias yang akan menggunakan AssertJ API (mirip dengan menggunakanassertThat(ex).hasNoCause()...
). Pada titik tertentu proyek ini mengandalkan FEST-Assert, leluhur AssertJ . EDIT: Tampaknya proyek ini sedang menyedot dukungan Java 8 Lambdas.Saat ini, perpustakaan ini memiliki dua kekurangan:
Pada saat penulisan ini, perlu dicatat untuk mengatakan perpustakaan ini didasarkan pada Mockito 1.x karena menciptakan tiruan dari objek yang diuji di belakang layar. Karena Mockito masih belum diperbarui perpustakaan ini tidak dapat bekerja dengan kelas akhir atau metode akhir . Dan bahkan jika itu didasarkan pada Mockito 2 dalam versi saat ini, ini akan perlu untuk menyatakan pembuat mock global (
inline-mock-maker
), sesuatu yang mungkin tidak seperti yang Anda inginkan, karena pembuat tiruan ini memiliki kelemahan berbeda dari pembuat tiruan biasa.Ini membutuhkan lagi ketergantungan tes.
Masalah ini tidak akan berlaku setelah perpustakaan mendukung lambdas. Namun, fungsionalitas akan diduplikasi oleh toolset AssertJ.
Mempertimbangkan semua jika Anda tidak ingin menggunakan alat catch-exception, saya akan merekomendasikan cara lama yang baik
try
-catch
blok, setidaknya hingga JDK7. Dan untuk pengguna JDK 8 Anda mungkin lebih suka menggunakan AssertJ karena menawarkan mungkin lebih dari sekadar menegaskan pengecualian.Dengan JDK8, lambdas memasuki panggung tes, dan mereka telah terbukti menjadi cara yang menarik untuk menegaskan perilaku yang luar biasa. AssertJ telah diperbarui untuk menyediakan API lancar yang bagus untuk menegaskan perilaku yang luar biasa.
Dan tes sampel dengan AssertJ :
Dengan penulisan ulang hampir lengkap dari JUnit 5, pernyataan telah sedikit ditingkatkan , mereka mungkin terbukti menarik sebagai cara di luar kotak untuk menyatakan pengecualian dengan benar. Tapi sungguh-sungguh API pernyataan masih sedikit miskin, tidak ada di luar
assertThrows
.Seperti yang Anda perhatikan
assertEquals
masih kembalivoid
, dan karena itu tidak memungkinkan pernyataan rantai seperti AssertJ.Juga jika Anda ingat nama bentrokan dengan
Matcher
atauAssert
, bersiaplah untuk bertemu dengan bentrokan yang samaAssertions
.Saya ingin menyimpulkan bahwa hari ini (2017-03-03) AssertJ 's kemudahan penggunaan, API yang dapat ditemukan, laju pengembangan yang cepat dan sebagai ketergantungan uji de facto adalah solusi terbaik dengan JDK8 terlepas dari kerangka pengujian (JUnit atau tidak), JDK sebelumnya seharusnya bergantung pada
try
-catch
blok bahkan jika mereka merasa kikuk.Jawaban ini telah disalin dari pertanyaan lain yang tidak memiliki visibilitas yang sama, saya adalah penulis yang sama.
sumber
Sekarang JUnit 5 dan JUnit 4.13 telah dirilis, opsi terbaik adalah menggunakan
Assertions.assertThrows()
(untuk JUnit 5) danAssert.assertThrows()
(untuk JUnit 4.13). Lihat Panduan Pengguna Junit 5 .Berikut adalah contoh yang memverifikasi pengecualian dilempar, dan menggunakan Kebenaran untuk membuat pernyataan tegas pada pesan pengecualian:
Keuntungan dari pendekatan dalam jawaban lain adalah:
throws
klausaMetode serupa akan ditambahkan ke
org.junit Assert
dalam JUnit 4.13.sumber
Bagaimana dengan ini: Tangkap pengecualian yang sangat umum, pastikan itu keluar dari blok tangkap, kemudian tegaskan bahwa kelas pengecualian adalah apa yang Anda harapkan. Penegasan ini akan gagal jika a) pengecualiannya dari tipe yang salah (mis. Jika Anda mendapat Null Pointer sebagai gantinya) dan b) pengecualian tidak pernah dilempar.
sumber
assertEquals(ExpectedException.class, e.getClass())
akan menunjukkan kepada Anda nilai yang diharapkan dan aktual ketika tes gagal.Solusi Gaya BDD : JUnit 4 + Catch Exception + AssertJ
Ketergantungan
sumber
Menggunakan pernyataan AssertJ , yang dapat digunakan bersama JUnit:
Ini lebih baik daripada
@Test(expected=IndexOutOfBoundsException.class)
karena itu menjamin garis yang diharapkan dalam tes melemparkan pengecualian dan memungkinkan Anda memeriksa detail lebih lanjut tentang pengecualian, seperti pesan, lebih mudah:Instruksi Maven / Gradle di sini.
sumber
assertThat
, selalu yang AssertJ. Juga metode JUnit mengembalikan hanya tipe "biasa", sedangkan metode AssertJ mengembalikanAbstractAssert
subclass ... memungkinkan merangkai metode seperti di atas (atau apa pun istilah teknisnya untuk ini ...).Untuk mengatasi masalah yang sama, saya membuat proyek kecil: http://code.google.com/p/catch-exception/
Dengan bantuan kecil ini, Anda akan menulis
Ini kurang verbose dari aturan ExpectedException pada JUnit 4.7. Dibandingkan dengan solusi yang disediakan oleh skaffman, Anda dapat menentukan di baris kode mana Anda mengharapkan pengecualian. Saya harap ini membantu.
sumber
foo
inifinal
akan gagal karena Anda tidak dapat proksifoo
?Update: JUnit5 memiliki perbaikan untuk pengecualian pengujian:
assertThrows
.contoh berikut adalah dari: Panduan Pengguna Junit 5
Jawaban asli menggunakan JUnit 4.
Ada beberapa cara untuk menguji apakah pengecualian dilemparkan. Saya juga telah membahas opsi di bawah ini dalam posting saya. Bagaimana cara menulis unit test dengan JUnit?
Atur
expected
parameternya@Test(expected = FileNotFoundException.class)
.Menggunakan
try
catch
Pengujian dengan
ExpectedException
Aturan.Anda dapat membaca lebih lanjut tentang pengujian pengecualian di wiki JUnit4 untuk pengujian Pengecualian dan bad.robot - Mengharapkan Pengecualian Aturan JUnit .
sumber
Anda juga dapat melakukan ini:
sumber
Assert.fail()
, tidakassert
, kalau-kalau tes Anda berjalan di lingkungan di mana pernyataan tidak diaktifkan.IMHO, cara terbaik untuk memeriksa pengecualian di JUnit adalah pola coba / tangkap / gagal / tegaskan:
The
assertTrue
mungkin agak kuat bagi sebagian orang, jadiassertThat(e.getMessage(), containsString("the message");
mungkin lebih baik.sumber
JUnit 5 Solusi
Lebih banyak info tentang JUnit 5 di http://junit.org/junit5/docs/current/user-guide/#writing-tests-assertions
sumber
expectThrows()
adalah bagian dari TestNG, bukan JUnitJawaban paling fleksibel dan elegan untuk Junit 4 saya temukan di blog Mkyong . Ini memiliki fleksibilitas
try/catch
menggunakan@Rule
anotasi. Saya suka pendekatan ini karena Anda dapat membaca atribut spesifik pengecualian khusus.sumber
Saya mencoba banyak metode di sini, tetapi mereka rumit atau tidak memenuhi persyaratan saya. Bahkan, seseorang dapat menulis metode pembantu dengan cukup sederhana:
Gunakan seperti ini:
Zero dependency: tidak perlu untuk mockito, tidak perlu powermock; dan bekerja dengan baik dengan kelas akhir.
sumber
Solusi Java 8
Jika Anda menginginkan solusi yang:
Berikut adalah fungsi utilitas yang saya tulis:
( diambil dari blog saya )
Gunakan sebagai berikut:
sumber
JUnit memiliki dukungan bawaan untuk ini, dengan atribut "yang diharapkan"
sumber
Dalam kasus saya, saya selalu mendapatkan RuntimeException dari db, tetapi pesan berbeda. Dan pengecualian harus ditangani masing-masing. Inilah cara saya mengujinya:
sumber
} catch (
, Anda harus memasukkanfail("no exception thrown");
Buat saja Pencocokan yang bisa dimatikan dan dinyalakan, seperti ini:
Untuk menggunakannya:
tambahkan
public ExpectedException exception = ExpectedException.none();
, lalu:sumber
Di JUnit 4 atau lebih baru Anda dapat menguji pengecualian sebagai berikut
ini menyediakan banyak fitur yang dapat digunakan untuk meningkatkan tes JUnit kami.
Jika Anda melihat contoh di bawah ini saya menguji 3 hal dengan pengecualian.
sumber
Kita bisa menggunakan pernyataan gagal setelah metode yang harus mengembalikan pengecualian:
sumber
catch
akan menelan jejak stack jika beberapa pengecualian lain dilemparkan, kehilangan informasi yang bermanfaatSelain apa yang dikatakan NamShubWriter , pastikan bahwa:
Jangan tidak melakukan hal ini:
Akhirnya, posting blog ini dengan jelas menggambarkan cara untuk menegaskan bahwa pengecualian tertentu dilemparkan.
sumber
Saya merekomendasikan perpustakaan
assertj-core
untuk menangani pengecualian dalam tes junitDi java 8, seperti ini:
sumber
Solusi Junit4 dengan Java8 adalah dengan menggunakan fungsi ini:
Maka penggunaan adalah:
Perhatikan bahwa satu-satunya batasan adalah menggunakan
final
referensi objek dalam ekspresi lambda. Solusi ini memungkinkan untuk melanjutkan pernyataan pengujian alih-alih mengharapkan yang dapat dicapai pada tingkat metode menggunakan@Test(expected = IndexOutOfBoundsException.class)
solusi.sumber
Ambil contoh, Anda ingin menulis Junit untuk fragmen kode yang disebutkan di bawah ini
Kode di atas adalah untuk menguji beberapa pengecualian yang tidak diketahui yang mungkin terjadi dan yang di bawah ini adalah untuk menegaskan beberapa pengecualian dengan pesan khusus.
sumber
Berikut cara lain untuk mengecek metode melempar pengecualian yang benar atau tidak.
sumber
Kerangka kerja JUnit memiliki
assertThrows()
metode:org.junit.jupiter.api.Assertions
kelas;org.junit.Assert
kelas;org.junit.jupiter:junit-jupiter-api
ke proyek Anda dan Anda akan mendapatkan versi yang berfungsi dengan baik dari JUnit 5.sumber
Dengan Java 8 Anda dapat membuat metode mengambil kode untuk memeriksa dan pengecualian yang diharapkan sebagai parameter:
dan kemudian di dalam tes Anda:
Manfaat:
sumber