it-swarm-id.com

Bagaimana cara menulis unit test "baik"?

Dipicu oleh tas ini , saya (sekali lagi) berpikir untuk akhirnya menggunakan unit test dalam proyek saya. Beberapa poster di sana mengatakan sesuatu seperti "Tes itu keren, jika itu tes yang bagus". Pertanyaan saya sekarang: Apa itu tes "baik"?

Dalam aplikasi saya, bagian utama sering kali adalah semacam analisis numerik, tergantung pada sejumlah besar data yang diamati, dan menghasilkan fungsi fit yang dapat digunakan untuk memodelkan data ini. Saya merasa sangat sulit untuk membangun tes untuk metode ini, karena jumlah input dan hasil yang mungkin terlalu besar untuk hanya menguji setiap kasus, dan metode itu sendiri seringkali agak gondrong dan tidak dapat dengan mudah di refactored tanpa mengorbankan kinerja. Saya terutama tertarik pada tes "baik" untuk metode semacam ini.

63
Jens

The Art of Unit Testing memiliki pendapat berikut tentang pengujian unit:

Tes unit harus memiliki properti berikut:

  • Itu harus otomatis dan berulang.
  • Seharusnya mudah diimplementasikan.
  • Setelah ditulis, harus tetap untuk digunakan di masa mendatang.
  • Siapa pun harus dapat menjalankannya.
  • Ini harus dijalankan dengan menekan tombol.
  • Itu harus berjalan cepat.

dan kemudian menambahkannya harus sepenuhnya otomatis, dapat dipercaya, dapat dibaca, dan dipelihara.

Saya sangat merekomendasikan membaca buku ini jika Anda belum melakukannya.

Menurut pendapat saya, semua ini sangat penting, tetapi tiga yang terakhir (dapat dipercaya, dapat dibaca, dan dipelihara) terutama, seolah-olah tes Anda memiliki tiga properti ini maka kode Anda biasanya juga memilikinya.

52
Andy Lowry

Tes unit yang baik tidak mencerminkan fungsi yang sedang diuji.

Sebagai contoh yang sangat sederhana, anggap Anda memiliki fungsi yang mengembalikan rata-rata dua int. Tes yang paling komprehensif akan memanggil fungsi dan memeriksa apakah hasilnya ternyata rata-rata. Ini sama sekali tidak masuk akal: Anda sedang meniru (mereplikasi) fungsionalitas yang Anda uji. Jika Anda membuat kesalahan dalam fungsi utama, Anda akan membuat kesalahan yang sama dalam ujian.

Dengan kata lain, jika Anda mereplikasi fungsi utama dalam tes unit, itu adalah tanda bahwa Anda membuang-buang waktu.

43
mojuba

Tes unit yang baik pada dasarnya adalah spesifikasi dalam bentuk runnable:

  1. menjelaskan perilaku kode yang sesuai dengan kasus penggunaan
  2. mencakup kasus sudut teknis (apa yang terjadi jika nol dilewatkan) - jika tes tidak ada untuk kasus sudut, perilaku tidak ditentukan.
  3. istirahat jika kode yang diuji berubah dari spesifikasi

Saya telah menemukan Test-Driven-Development sangat cocok untuk rutinitas perpustakaan ketika Anda pada dasarnya menulis API terlebih dahulu, dan MAKA implementasi yang sebenarnya.

10
user1249

untuk TDD, "baik" tes tes fitur yang diinginkan pelanggan ; fitur tidak harus sesuai dengan fungsi, dan skenario pengujian tidak boleh dibuat oleh pengembang dalam ruang hampa

dalam kasus Anda - saya menduga - 'fitur' adalah bahwa fungsi fit memodelkan data input dalam toleransi kesalahan tertentu. Karena saya tidak tahu apa yang sebenarnya Anda lakukan, saya mengarang sesuatu; semoga itu analgous.

Contoh cerita:

Sebagai [Pilot X-Wing] saya ingin [tidak lebih dari 0,0001% kesalahan pas] sehingga [komputer penargetan dapat mengenai port knalpot Death Star ketika bergerak dengan kecepatan penuh melalui ngarai kotak]

Jadi Anda berbicara dengan pilot (dan ke komputer penargetan, jika hidup). Pertama Anda berbicara tentang apa yang 'normal', kemudian berbicara tentang yang tidak normal. Anda mencari tahu apa yang sebenarnya penting dalam skenario ini, apa yang umum, apa yang tidak mungkin, dan apa yang hanya mungkin.

Katakanlah bahwa biasanya Anda akan memiliki jendela setengah detik lebih dari tujuh saluran data telemetri: kecepatan, pitch, roll, menguap, vektor target, ukuran target, dan kecepatan target, dan bahwa nilai-nilai ini akan konstan atau berubah secara linear. Abnormal Anda mungkin memiliki lebih sedikit saluran dan/atau nilainya dapat berubah dengan cepat. Jadi bersama-sama Anda membuat beberapa tes seperti:

//Scenario 1 - can you hit the side of a barn?
Given:
    all 7 channels with no dropouts for the full half-second window,
When:
    speed is zero
    and target velocity is zero
    and all other values are constant,
Then:
    the error coefficient must be zero

//Scenario 2 - can you hit a turtle?
Given:
    all 7 channels with no dropouts for the full half-second window,
When:
    speed is zero
    and target velocity is less than c
    and all other values are constant,
Then:
    the error coefficient must be less than 0.0000000001/ns

...

//Scenario 42 - death blossom
Given:
    all 7 channels with 30% dropout and a 0.05 second sampling window
When:
    speed is zero
    and position is within enemy cluster
    and all targets are stationary
Then:
    the error coefficient must be less than 0.000001/ns for each target

Sekarang, Anda mungkin telah memperhatikan bahwa tidak ada skenario untuk situasi tertentu yang dijelaskan dalam cerita. Ternyata, setelah berbicara dengan pelanggan dan pemangku kepentingan lainnya, tujuan dalam cerita asli hanyalah contoh hipotetis. Tes nyata keluar dari diskusi berikutnya. Ini bisa terjadi. Ceritanya harus ditulis ulang, tetapi tidak harus [karena ceritanya hanyalah pengganti untuk percakapan dengan pelanggan].

7
Steven A. Lowe

Buat tes untuk kasing sudut, seperti set tes yang hanya berisi jumlah input minimum (mungkin 1 atau 0) dan beberapa kasing standar. Tes-tes unit itu bukan pengganti untuk tes penerimaan menyeluruh, juga tidak seharusnya demikian.

5
user281377

Saya telah melihat banyak kasus di mana orang menginvestasikan sejumlah besar upaya menulis tes untuk kode yang jarang dimasukkan, dan tidak menulis tes untuk kode yang sering dimasukkan.

Sebelum duduk untuk menulis tes apa pun, Anda harus melihat semacam grafik panggilan, untuk memastikan Anda merencanakan cakupan yang memadai.

Selain itu, saya tidak percaya pada tes menulis hanya untuk mengatakan "Ya, kami menguji itu". Jika saya menggunakan pustaka yang dijatuhkan dan akan tetap tidak berubah, saya tidak akan menyia-nyiakan tes menulis sehari untuk memastikan jeroan API yang tidak akan pernah berubah berfungsi seperti yang diharapkan, bahkan jika bagian tertentu dari skor itu tinggi pada grafik panggilan. Tes yang mengkonsumsi kata perpustakaan (kode saya sendiri) menunjukkan ini.

5
Tim Post

Tidak begitu TDD, tetapi setelah Anda masuk ke QA Anda dapat meningkatkan tes Anda dengan mengatur kasus uji untuk mereproduksi bug yang muncul selama proses QA. Ini bisa sangat berharga ketika Anda pergi ke dukungan jangka panjang dan Anda mulai pergi ke tempat di mana Anda berisiko orang secara tidak sengaja memperkenalkan kembali bug lama. Memiliki tes untuk menangkap yang sangat berharga.

4
glenatron

Saya mencoba agar setiap tes hanya menguji satu hal. Saya mencoba memberi setiap tes nama seperti shouldDoSomething (). Saya mencoba menguji perilaku, bukan implementasi. Saya hanya menguji metode publik.

Saya biasanya memiliki satu atau beberapa tes untuk sukses, dan kemudian mungkin beberapa tes untuk kegagalan, per metode publik.

Saya sering menggunakan mock-up. Mock-framework yang baik mungkin akan sangat membantu, seperti PowerMock. Meskipun saya belum menggunakannya.

Jika kelas A menggunakan kelas B lain, saya akan menambahkan antarmuka, X, sehingga A tidak menggunakan B secara langsung. Lalu saya akan membuat mock-up XMockup dan menggunakannya sebagai pengganti B dalam pengujian saya. Ini benar-benar membantu mempercepat pelaksanaan pengujian, mengurangi kompleksitas pengujian, dan juga mengurangi jumlah tes yang saya tulis untuk A karena saya tidak harus mengatasi kekhasan B. Saya dapat misalnya menguji bahwa A memanggil X.someMethod () alih-alih efek samping dari memanggil B.someMethod ().

Pastikan Anda juga menguji kode.

Saat menggunakan API, seperti lapisan basis data, saya akan mengejeknya dan memungkinkan mock-up untuk melemparkan pengecualian di setiap peluang yang ada pada perintah. Saya kemudian menjalankan tes satu tanpa melempar, dan dalam satu lingkaran, setiap kali melempar pengecualian pada kesempatan berikutnya sampai tes berhasil lagi. Agak seperti tes memori yang tersedia untuk Symbian.

3

Saya melihat bahwa Andry Lowry telah memposting metrik pengujian unit Roy Osherove; tetapi tampaknya tidak ada yang memberikan set (gratis) yang diberikan Paman Bob Kode Bersih (132-133). Dia menggunakan akronim PERTAMA (di sini dengan ringkasan saya):

  • Cepat (mereka harus berjalan dengan cepat, jadi orang tidak akan keberatan menjalankannya)
  • Independen (tes tidak boleh melakukan setup atau teardown satu sama lain)
  • Diulang (harus berjalan di semua lingkungan/platform)
  • Memvalidasi sendiri (sepenuhnya otomatis; output harus berupa "lulus" atau "gagal", bukan file log)
  • Tepat wakt (kapan harus menulisnya — tepat sebelum menulis kode produksi yang mereka uji)
2
Kazark