Bagaimana Anda menulis kasus uji unit?

14

Kadang-kadang saya akhirnya menulis kasus uji unit untuk kode yang telah ditulis pengembang lain. Ada saat-saat ketika saya benar-benar tidak tahu apa yang coba dilakukan oleh pengembang (bagian bisnis) dan saya hanya memanipulasi test case untuk mendapatkan garis hijau. Apakah hal-hal ini normal dalam industri?

Apa tren normal? Apakah pengembang seharusnya menulis kasus uji unit untuk kode yang mereka tulis sendiri?

Vinoth Kumar CM
sumber
2
"Tidak"? Apa artinya "tidak"?
S.Lott

Jawaban:

12

Coba baca posting blog ini: Menulis Tes Unit Hebat: Praktik Terbaik dan Terburuk .

Tetapi ada banyak orang lain di web.

Sebagai jawaban langsung untuk pertanyaan Anda ...

  1. "Tren normal" - Saya kira ini bisa berbeda dari satu tempat ke tempat lain, apa yang normal bagi saya mungkin aneh bagi orang lain.
  2. Saya akan mengatakan (dalam opsi saya) pengembang yang menulis kode harus menulis tes, idealnya menggunakan metode seperti TDD, di mana Anda akan menulis tes sebelum kode. Tetapi yang lain mungkin memiliki metode dan ide yang berbeda di sini!

Dan cara Anda menggambarkan penulisan tes (dalam pertanyaan Anda) benar-benar salah !!


sumber
9

Pendekatan ini membuat unit test tidak berharga.

Anda harus memiliki unit test gagal ketika beberapa tindakan nyata tidak berfungsi sebagaimana dimaksud. Jika Anda tidak melakukannya seperti itu, dan mungkin bahkan menulis tes sebelum kode untuk diuji, itu seperti memiliki alarm asap yang tidak berfungsi.


sumber
8
Ini tidak sepenuhnya benar. Atau lebih tepatnya, itu benar di dunia yang ideal, tetapi sayangnya, seringkali kita jauh dari itu. Pertimbangkan untuk memiliki kode lama tanpa pengujian dan tanpa spesifikasi, dan tanpa siapa pun yang dapat memberi tahu Anda detail hingga menit terakhir, apa yang seharusnya dilakukan oleh sepotong kode tertentu (ini adalah kenyataan dalam sebagian besar proyek yang ada). Bahkan dalam kasus ini, mungkin masih layak untuk menulis unit test untuk mengunci status kode saat ini, dan untuk memastikan bahwa Anda tidak merusak apa pun dengan refactoring, perbaikan bug, atau ekstensi di masa mendatang.
Péter Török
2
Juga, saya kira Anda bermaksud "menulis tes setelah kode untuk menguji", bukan?
Péter Török
@ Péter, kata-katanya salah - Anda benar. Tetapi, jika Anda memutuskan untuk menulis tes, mereka harus melakukan sesuatu agar bermanfaat. Hanya dengan membabi buta memanggil kode yang mengatakan itu adalah ujian, adalah - menurut saya - bukan pengujian.
Jadi, jika Anda bermaksud bahwa kami harus memiliki pernyataan yang bermakna dalam pengujian unit kami, untuk memverifikasi bahwa kode yang diuji memang melakukan apa yang kami pikir benar, saya sepenuhnya setuju.
Péter Török
3

Jika Anda tidak tahu apa fungsi tidak maka Anda tidak dapat menulis tes unit untuk itu. Untuk semua yang Anda tahu itu bahkan tidak melakukan apa yang seharusnya. Anda perlu mencari tahu apa yang seharusnya dilakukan terlebih dahulu. MAKA tulis tes.

Edward Strange
sumber
3

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:

  1. bahwa ia dapat mengembalikan root sederhana seperti sqrt (4.0)
  2. bahwa ia dapat menemukan root nyata seperti sqrt (2.0) dengan presisi yang masuk akal
  3. bahwa ia menemukan bahwa sqrt (0,0) adalah 0,0
  4. 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.01dan 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.

wallenborn
sumber
1

Ketika saya menulis test case (untuk printer) saya mencoba memikirkan setiap komponen kecil .... dan apa yang bisa saya lakukan untuk memecahkannya. Jadi misalkan pemindai misalnya, perintah apa yang digunakan (dalam bahasa-printer-pekerjaan pjl) apa yang bisa saya tulis untuk menguji setiap fungsionalitas .... Oke sekarang apa yang bisa saya lakukan untuk mencoba dan memecahkannya.

Saya mencoba melakukan itu untuk setiap komponen utama, tetapi ketika datang ke perangkat lunak dan tidak terlalu banyak perangkat keras Anda ingin melihat setiap metode / fungsi dan memeriksa batas-batas dan semacamnya.


sumber
1

Sepertinya Anda bekerja dengan pengembang lain (atau mempertahankan kode yang ditulis oleh pengembang lain) yang tidak melakukan pengujian unit. Dalam hal ini, saya pikir Anda pasti ingin tahu apa objek atau metode yang Anda uji lakukan, lalu buat tes untuk itu.

Bukan TDD karena Anda tidak menulis tes terlebih dahulu, tetapi Anda dapat memperbaiki situasinya. Anda mungkin juga ingin membuat salinan objek yang diuji dengan bertopik sehingga dapat memastikan bahwa tes Anda berfungsi dengan baik ketika kode gagal.

vjones
sumber