Di Dunia Nyata, sangat normal untuk menulis unit test untuk kode orang lain. Tentu, pengembang asli seharusnya sudah melakukan ini, tetapi sering kali Anda menerima kode lama di mana ini tidak dilakukan. Ngomong-ngomong, tidak masalah apakah kode warisan itu datang beberapa dekade yang lalu dari galaksi jauh, jauh, atau apakah salah satu rekan kerja Anda memeriksanya minggu lalu, atau apakah Anda menulisnya hari ini, kode warisan adalah kode tanpa tes
Tanyakan kepada diri sendiri: mengapa kita menulis unit test? Going Green jelas hanya sarana untuk mencapai tujuan, tujuan utamanya adalah untuk membuktikan atau menyangkal pernyataan tentang kode yang sedang diuji.
Katakanlah Anda memiliki metode yang menghitung akar kuadrat dari angka floating-point. Di Jawa, antarmuka akan mendefinisikannya sebagai:
public double squareRoot(double number);
Tidak masalah apakah Anda menulis implementasinya atau apakah orang lain melakukannya, Anda ingin menegaskan beberapa properti squareRoot:
- bahwa ia dapat mengembalikan root sederhana seperti sqrt (4.0)
- bahwa ia dapat menemukan root nyata seperti sqrt (2.0) dengan presisi yang masuk akal
- bahwa ia menemukan bahwa sqrt (0,0) adalah 0,0
- bahwa itu melempar IllegalArgumentException ketika diberi makan angka negatif, yaitu pada sqrt (-1.0)
Jadi Anda mulai menulis ini sebagai tes individual:
@Test
public void canFindSimpleRoot() {
assertEquals(2, squareRoot(4), epsilon);
}
Ups, tes ini sudah gagal:
java.lang.AssertionError: Use assertEquals(expected, actual, delta) to compare floating-point numbers
Anda lupa tentang aritmatika floating point. Oke, Anda memperkenalkan double epsilon=0.01
dan pergi:
@Test
public void canFindSimpleRootToEpsilonPrecision() {
assertEquals(2, squareRoot(4), epsilon);
}
dan tambahkan tes lainnya: akhirnya
@Test
@ExpectedException(IllegalArgumentException.class)
public void throwsExceptionOnNegativeInput() {
assertEquals(-1, squareRoot(-1), epsilon);
}
dan oops, sekali lagi:
java.lang.AssertionError: expected:<-1.0> but was:<NaN>
Anda harus menguji:
@Test
public void returnsNaNOnNegativeInput() {
assertEquals(Double.NaN, squareRoot(-1), epsilon);
}
Apa yang sudah kita lakukan di sini? Kami mulai dengan beberapa asumsi tentang bagaimana metode harus berperilaku, dan menemukan bahwa tidak semua benar. Kami kemudian membuat test suite Green, untuk menuliskan bukti bahwa metode tersebut berperilaku sesuai dengan asumsi kami yang dikoreksi. Sekarang klien dari kode ini dapat mengandalkan perilaku ini. Jika seseorang menukar implementasi aktual SquareRoot dengan sesuatu yang lain, sesuatu yang misalnya benar-benar melemparkan pengecualian alih-alih mengembalikan NaN, pengujian kami akan langsung menangkapnya.
Contoh ini sepele, tetapi seringkali Anda mewarisi potongan kode besar di mana tidak jelas apa yang sebenarnya dilakukannya. Dalam hal ini, adalah normal untuk meletakkan test harness di sekitar kode. Mulailah dengan beberapa asumsi dasar tentang bagaimana kode seharusnya berperilaku, tulis tes unit untuk mereka, tes. Jika Hijau, bagus, tulis lebih banyak tes. Jika Red, nah sekarang Anda memiliki pernyataan gagal yang dapat Anda pertahankan terhadap sebuah spec. Mungkin ada bug dalam kode warisan. Mungkin spek tidak jelas tentang input khusus ini. Mungkin Anda tidak memiliki spec. Dalam hal itu, tulis ulang tes sehingga mendokumentasikan perilaku yang tidak terduga:
@Test
public void throwsNoExceptionOnNegativeInput() {
assertNotNull(squareRoot(-1)); // Shouldn't this fail?
}
Seiring waktu, Anda berakhir dengan memanfaatkan uji yang mendokumentasikan bagaimana kode sebenarnya berperilaku, dan menjadi semacam spesifikasi kode. Jika Anda ingin mengubah kode lawas, atau menggantinya dengan yang lain, Anda memiliki test harness untuk memverifikasi bahwa kode baru berperilaku sama, atau bahwa kode baru berperilaku berbeda dalam cara yang diharapkan dan dikendalikan (misalnya bahwa itu sebenarnya memperbaiki bug yang Anda harapkan akan diperbaiki). Harness ini tidak harus lengkap pada hari pertama, pada kenyataannya, memiliki harness yang tidak lengkap hampir selalu lebih baik daripada tidak memiliki harness sama sekali. Memiliki tali kekang berarti Anda dapat menulis kode klien Anda dengan lebih mudah, Anda tahu di mana harus mengharapkan sesuatu akan rusak ketika Anda mengubah sesuatu, dan di mana mereka melanggar ketika mereka akhirnya melakukannya.
Anda harus mencoba keluar dari pola pikir bahwa Anda harus menulis tes unit hanya karena Anda harus, seperti Anda akan mengisi bidang wajib pada formulir. Dan Anda tidak harus menulis unit test hanya untuk membuat garis merah berwarna hijau. Unit test bukan musuh Anda, unit test adalah teman Anda.