Java 8 membuat ini jauh lebih mudah, dan Kotlin / Scala jadi dua kali lipat.
Kita dapat menulis kelas utilitas kecil
class MyAssertions{
public static void assertDoesNotThrow(FailingRunnable action){
try{
action.run()
}
catch(Exception ex){
throw new Error("expected action not to throw, but it did!", ex)
}
}
}
@FunctionalInterface interface FailingRunnable { void run() throws Exception }
dan kemudian kode Anda menjadi sederhana:
@Test
public void foo(){
MyAssertions.assertDoesNotThrow(() -> {
//execute code that you expect not to throw Exceptions.
}
}
Jika Anda tidak memiliki akses ke Java-8, saya akan menggunakan fasilitas java lama yang menyakitkan: blok kode aribitrary dan komentar sederhana
//setup
Component component = new Component();
//act
configure(component);
//assert
/*assert does not throw*/{
component.doSomething();
}
Dan akhirnya, dengan kotlin, sebuah bahasa yang saya baru saja jatuh cinta:
fun (() -> Any?).shouldNotThrow()
= try { invoke() } catch (ex : Exception){ throw Error("expected not to throw!", ex) }
@Test fun `when foo happens should not throw`(){
//...
{ /*code that shouldn't throw*/ }.shouldNotThrow()
}
Meskipun ada banyak ruang untuk bermain-main dengan persis bagaimana Anda ingin mengekspresikan ini, saya selalu penggemar pernyataan fasih .
Mengenai
Anda mendekati ini dengan cara yang salah. Cukup uji fungsionalitas Anda: jika ada pengecualian, pengujian akan gagal secara otomatis. Jika tidak ada pengecualian yang dilemparkan, semua pengujian Anda akan berubah menjadi hijau.
Ini pada prinsipnya benar tetapi kesimpulannya salah.
Java memungkinkan pengecualian untuk aliran kontrol. Ini dilakukan oleh runtime JRE sendiri dalam API seperti Double.parseDouble
via NumberFormatException
dan Paths.get
via a InvalidPathException
.
Mengingat Anda telah menulis komponen yang memvalidasi string Number untuk Double.ParseDouble
, mungkin menggunakan Regex, mungkin parser yang ditulis tangan, atau mungkin sesuatu yang menyematkan beberapa aturan domain lain yang membatasi rentang ganda untuk sesuatu yang spesifik, cara terbaik untuk menguji ini komponen? Saya pikir tes yang jelas akan menyatakan bahwa, ketika string yang dihasilkan diuraikan, tidak ada pengecualian yang dilemparkan. Saya akan menulis tes menggunakan salah satu di atas assertDoesNotThrow
atau /*comment*/{code}
blok. Sesuatu seperti
@Test public void given_validator_accepts_string_result_should_be_interpretable_by_doubleParseDouble(){
//setup
String input = "12.34E+26" //a string double with domain significance
//act
boolean isValid = component.validate(input)
//assert -- using the library 'assertJ', my personal favourite
assertThat(isValid).describedAs(input + " was considered valid by component").isTrue();
assertDoesNotThrow(() -> Double.parseDouble(input));
}
Saya juga mendorong Anda untuk membuat parameter tes ini saat input
menggunakan Theories
atau Parameterized
agar Anda dapat lebih mudah menggunakan kembali tes ini untuk input lain. Atau, jika Anda ingin menjadi eksotis, Anda bisa menggunakan alat generasi tes (dan ini ). TestNG memiliki dukungan yang lebih baik untuk pengujian parameter.
Apa yang menurut saya sangat tidak menyenangkan adalah rekomendasi untuk menggunakan @Test(expectedException=IllegalArgumentException.class)
, pengecualian ini sangat luas . Jika kode Anda berubah sedemikian rupa sehingga komponen di bawah konstruktor tes memiliki if(constructorArgument <= 0) throw IllegalArgumentException()
, dan tes Anda memasok 0 untuk argumen itu karena nyaman - dan ini sangat umum, karena data uji menghasilkan yang baik adalah masalah yang sangat sulit--, maka tes Anda akan menjadi bilah hijau meskipun tidak menguji apa pun. Tes semacam itu lebih buruk daripada tidak berguna.