fungsi dan / atau kelas apa yang tidak mungkin untuk diuji unit dan mengapa

21

Alasan utama dari pengembang untuk tidak memiliki pengujian unit yang baik adalah "Kode tidak dirancang dengan cara unit yang dapat diuji." Saya mencoba memahami jenis desain dan kode apa yang tidak dapat diuji unit.

manizzzz
sumber
2
Alasan anda? Seorang rekan kerja? Manajer? Bahasa / kerangka apa yang Anda kerjakan?
1
Banyak kode lawas dalam aplikasi dan tidak ada waktu untuk mendesain ulang.
knut
4
@gnat: Saya tidak setuju. Pertanyaan yang Anda kutip adalah tentang situasi di mana tes unit tidak berguna. Pertanyaan saat ini adalah tentang situasi yang membuat unit test sulit.
Arseni Mourzenko
@MainMa rupanya kami membaca pertanyaan yang berbeda. "Saya mencoba memahami jenis desain dan kode apa yang tidak dapat diuji unit." => "Kapan tepat untuk tidak menguji unit?"
nyamuk
1
@ manizzzz: Anda mungkin ingin mengeditnya menjadi pertanyaan.
jmoreno

Jawaban:

27

Beberapa faktor dapat menyebabkan kode sulit untuk diuji unit. Ketika hal ini terjadi, refactoring membantu dalam meningkatkan kode agar dapat diuji.

Beberapa contoh kode yang mungkin sulit untuk diuji:

  • Fungsi 1000-LOC,
  • Kode yang sangat bergantung pada negara global,
  • Kode yang membutuhkan konkret, rumit untuk membangun objek, seperti konteks basis data, alih-alih mengandalkan antarmuka dan Ketergantungan Injeksi,
  • Kode yang berkinerja lambat ,
  • Kode spageti,
  • Kode lama yang telah dimodifikasi selama bertahun-tahun tanpa peduli tentang keterbacaan atau pemeliharaan,
  • Sulit untuk memahami kode yang tidak memiliki komentar atau petunjuk tentang maksud asli penulis (misalnya kode yang menggunakan nama variabel seperti function pGetDp_U(int i, int i2, string sText).

Perhatikan bahwa kurangnya arsitektur yang jelas tidak membuat kode sulit untuk diuji unit, karena uji unit menyangkut bagian kecil dari kode. Arsitektur yang tidak jelas masih akan berdampak negatif pada integrasi dan pengujian sistem.

Arseni Mourzenko
sumber
8
Juga sulit untuk menguji kode yang tidak menyuntikkan dependensi pada fungsi yang tidak murni, seperti angka acak, waktu saat ini, I / O kabel, dll.
9000
itu sepele untuk menguji kode seperti itu - Anda hanya perlu alat uji yang tepat, bukan untuk memotong kode Anda agar sesuai dengan mereka. Coba Microsoft Fakes sebagai contoh.
gbjbaanb
@MainMa, saya suka jawaban ini. Apakah Anda juga bersedia berkomentar sedikit tentang faktor-faktor apa yang mendorong pengujian yang berbeda untuk integrasi dan pengujian sistem? Saya tahu bahwa alasan saya mengajukan pertanyaan serupa dengan yang ada di sini di masa lalu adalah karena saya tidak memiliki peta jalan yang menjelaskan jenis tes mana yang paling baik diletakkan di mana (atau mungkin, yang paling hemat biaya menempatkan di mana) - saya pikir unit test adalah satu-satunya.
J Trana
14

Ada banyak hal yang membuat kode sulit untuk diuji unit. Secara kebetulan banyak juga yang membuat kode sulit dipertahankan:

  • Pelanggaran Hukum Demeter .
  • Membuat objek di dalam metode alih-alih menyuntikkan dependensi .
  • Kopling ketat.
  • Kohesi yang buruk.
  • Sangat bergantung pada efek samping.
  • Sangat bergantung pada global atau lajang.
  • Tidak memaparkan banyak hasil antara. (Saya pernah harus menguji unit fungsi matematika sepuluh halaman panjang dengan output tunggal dan tidak ada hasil menengah yang tersedia. Para pendahulu saya pada dasarnya keras-kode apa pun jawaban kode yang terjadi untuk memberikan).
  • Sangat tergantung dan langsung pada layanan yang sulit untuk diejek, seperti database.
  • Lingkungan runtime secara signifikan berbeda dari lingkungan pengembangan, seperti target yang disematkan.
  • Unit hanya tersedia dalam bentuk yang dikompilasi (seperti DLL pihak ketiga).
Karl Bielefeldt
sumber
Saya pikir ini adalah jawaban yang sangat bagus. Anda menyentuh banyak masalah level kode, dan masalah kondisi global. @MainMa memiliki beberapa masalah lain yang saya pikir valid, tetapi kurang terdefinisi dengan baik. Jeffery Thomas menyebutkan I / O dan UI. Saya pikir jika Anda menambahkan bagian-bagian yang baik dari ketiga jawaban ini, Anda akan memiliki respons yang kohesif. Saya suka jawaban ini lebih baik karena fokus pada kode antipatterns.
M2tM
1
Argh - tidak ada yang lebih buruk daripada unit test yang menyatakan tidak memiliki kemiripan dengan persyaratan bisnis dan hanya output pada waktu tertentu - cemoohan yang diatur untuk dipanggil 3 kali misalnya? Mengapa 3? Karena ini adalah 3 pertama kalinya tes dijalankan / kata-kata kasar :)
Michael
Kopling ketat hanya buruk jika tidak sesuai. Kopling ketat dalam kode yang sangat kohesif adalah suatu keharusan. Misalnya deklarasi variabel diikuti oleh penggunaannya. Dipasangkan dengan erat, sangat kohesif.
dietbuddha
1
Tes unit di mana output diperiksa terhadap apa yang dilakukan kode, tanpa ada alasan / alasan bisnis, disebut Tes Karakterisasi. Mereka digunakan dalam pemeliharaan di mana sebelumnya tidak ada tes dan seringkali tidak ada persyaratan yang terdokumentasi dan Anda harus memasukkan sesuatu ke dalam yang akan rusak jika output dari fungsi itu berubah. Mereka lebih baik daripada tidak sama sekali.
Andy Krouwel
5

Contoh umum kode yang tidak ingin orang uji unit:

  • Kode yang berinteraksi langsung dengan i / o (membaca file, panggilan jaringan langsung, ...).
  • Kode yang secara langsung memperbarui UI.
  • Kode yang secara langsung merujuk pada lajang atau objek global.
  • Kode yang secara implisit mengubah objek atau keadaan sub-objek.

Menggunakan kerangka kerja tiruan, semua contoh ini dapat diuji unit. Ini hanya berfungsi untuk mengatur penggantian tiruan untuk dependensi internal.

Hal-hal yang benar-benar tidak dapat diuji unit:

  • Loop tak terbatas (untuk pengelola utas, driver, atau jenis kode berjalan lama lainnya)
  • Jenis operasi perakitan langsung tertentu (yang didukung beberapa bahasa)
  • Kode yang membutuhkan akses istimewa (bukan tidak mungkin, hanya bukan ide yang baik)
Jeffery Thomas
sumber
2

Ada beberapa area yang dapat membuatnya lebih sulit untuk menulis tes unit. Namun, saya akan menekankan bahwa itu tidak berarti Anda harus mengabaikan teknik yang berguna hanya karena mereka dapat menambah kompleksitas pada pengujian Anda. Seperti halnya pengkodean apa pun, Anda harus melakukan analisis sendiri untuk menentukan apakah manfaatnya melebihi biaya, dan tidak secara membabi buta menerima apa yang diposkan oleh beberapa lelaki acak di internet.

Kode desain dirancang dengan buruk

  • kopling tidak pantas (biasanya kopling ketat di tempat yang seharusnya tidak)
  • kode kitchen sink (di mana fungsi memiliki terlalu banyak logika / tanggung jawab)

Ketergantungan negara dalam ruang lingkup yang berbeda

Biaya untuk sebagian besar spiral ini di luar kendali kecuali Anda tahu apa yang Anda lakukan. Sayangnya, banyak yang tidak tahu bagaimana menggunakan teknik ini untuk mengurangi hal-hal seperti menguji kompleksitas.

  • Lajang
  • Global
  • Penutupan

Status Eksternal / Sistem

  • Ketergantungan perangkat keras / perangkat
  • Ketergantungan jaringan
  • Ketergantungan sistem file
  • Ketergantungan antar-proses
  • Ketergantungan sistem panggilan lainnya

Konkurensi

  • Threading (kunci, bagian kritis, dll)
  • fork'ing
  • Coroutine
  • Panggil Kembali
  • Penangan Sinyal (tidak semua, tetapi beberapa)
dietbuddha
sumber
2

Tidak ada kode yang tidak bisa diuji. Namun, ada beberapa contoh kode yang BENAR-BENAR sulit untuk diuji (sampai-sampai mungkin tidak sepadan dengan usaha):

Interaksi perangkat keras - Jika kode secara langsung memanipulasi perangkat keras (misalnya, menulis ke register untuk memindahkan perangkat fisik), maka unit pengujian mungkin terlalu sulit atau mahal. Jika Anda menggunakan perangkat keras nyata untuk pengujian, itu bisa menjadi mahal untuk mendapatkan umpan balik yang sesuai ke dalam harness uji (namun lebih banyak peralatan!), Dan jika tidak, Anda harus meniru perilaku yang tepat dari objek fisik - tidak ada trik kecil dalam beberapa contoh.

Interaksi jam - Ini biasanya lebih mudah, karena hampir selalu mungkin untuk mengejek fungsi sistem jam dengan sangat sepele. Tetapi ketika Anda tidak bisa, maka tes-tes ini menjadi tidak terkelola - tes yang didasarkan pada waktu nyata cenderung memakan waktu lama untuk dijalankan, dan dalam pengalaman saya mereka cenderung sangat rapuh karena beban sistem membuat hal-hal memakan waktu lebih lama daripada yang seharusnya , menyebabkan kegagalan tes hantu.

Michael Kohne
sumber
0

Tiga kelompok utama saya untuk ini adalah:

  • kode yang bergantung pada layanan eksternal

  • sistem yang tidak memungkinkan penguji untuk memodifikasi keadaan secara independen dari aplikasi.

  • lingkungan pengujian yang tidak mereplikasi pengaturan produksi.

Inilah yang paling saya alami ketika pengembang berubah menjadi insinyur QA.

Michael Durrant
sumber