Menulis tes untuk kode yang tujuannya tidak saya mengerti

59

Baru-baru ini saya menyelesaikan refactoring kotak hitam. Saya tidak dapat memeriksanya, karena saya tidak tahu cara mengujinya.

Pada level tinggi, saya memiliki kelas yang inisialisasi melibatkan mengambil nilai dari beberapa kelas B. Jika kelas B "kosong", itu menghasilkan beberapa default yang masuk akal. Saya mengekstrak bagian ini ke metode yang menginisialisasi kelas B ke default yang sama.

Saya belum mengetahui tujuan / konteks dari salah satu kelas, atau bagaimana mereka akan digunakan. Jadi saya tidak dapat menginisialisasi objek dari kelas B yang kosong dan memeriksa apakah ia memiliki nilai yang benar / melakukan hal yang benar.

Ide terbaik saya adalah menjalankan kode asli, hardcode dalam hasil metode publik tergantung pada anggota yang diinisialisasi, dan menguji kode baru terhadap hal itu. Saya tidak bisa mengartikulasikan mengapa saya merasa tidak nyaman dengan ide ini.

Apakah ada serangan yang lebih baik di sini?

JETM
sumber
28
Saya merasa Anda telah memulai pada ujung yang salah. Pertama-tama Anda harus memahami kode, lalu mengujinya, lalu refactor. Mengapa Anda refactoring tanpa mengetahui untuk apa kode itu?
Jacob Raihle
11
@JacobRaihle Ini adalah program yang agak khusus untuk orang-orang dengan gelar dalam hal-hal yang belum pernah saya sentuh. Saya mengambil konteks ketika saya mulai, tetapi tidak praktis untuk menunggu untuk memiliki pemahaman yang kuat sebelum saya mulai.
JETM
4
Apa yang tidak praktis adalah menulis ulang hal-hal dan, ketika perubahan dalam produksi, temukan mengapa Anda tidak harus melakukannya. Jika Anda dapat menguji secara menyeluruh sebelum itu, baiklah, ini bisa menjadi cara yang baik untuk mengenal basis kode. Jika tidak, itu penting bahwa Anda memahami sebelum Anda berubah.
Jacob Raihle
37
Ada jenis pengujian khusus yang disebut pengujian Karakterisasi ketika Anda ingin menguji perilaku aktual sistem. Anda hanya mengambil sistem asli Anda, lalu menambahkan tes yang menegaskan apa pun yang sebenarnya dilakukannya (dan belum tentu apa yang seharusnya dilakukan!). Mereka berfungsi sebagai perancah di sekitar sistem Anda, yang dapat Anda modifikasi dengan aman karena Anda dapat memastikan perilakunya tetap terjaga.
Vincent Savard
3
Tidak bisa Anda meminta / mendapatkannya ditinjau oleh seseorang yang tidak memahaminya?
pjc50

Jawaban:

122

Anda baik-baik saja!

Membuat tes regresi otomatis sering kali merupakan hal terbaik yang dapat Anda lakukan untuk membuat komponen dapat diulang kembali. Ini mungkin mengejutkan, tetapi tes semacam itu seringkali dapat ditulis tanpa pemahaman penuh tentang apa yang komponen lakukan secara internal, selama Anda memahami input dan output "antarmuka" (dalam arti umum kata itu). Kami melakukan ini beberapa kali di masa lalu untuk aplikasi warisan penuh, bukan hanya kelas, dan itu sering membantu kami menghindari hal-hal yang tidak kami pahami sepenuhnya.

Namun, Anda harus memiliki data uji yang cukup dan pastikan Anda memiliki pemahaman yang kuat tentang apa yang dilakukan perangkat lunak dari sudut pandang pengguna komponen itu, jika tidak, Anda berisiko menghilangkan kasus uji penting.

Ini adalah ide yang bagus untuk menerapkan tes otomatis Anda sebelum memulai refactoring, bukan setelahnya, sehingga Anda dapat melakukan refactoring dalam langkah-langkah kecil dan memverifikasi setiap langkah. Refactoring itu sendiri harus membuat kode lebih mudah dibaca, sehingga membantu Anda meningkatkan pemahaman Anda sedikit demi sedikit. Jadi langkah-langkah urutan dalam proses ini adalah

  1. dapatkan pengertian kode "dari luar",
  2. tulis tes regresi,
  3. refactor, yang mengarah pada pemahaman yang lebih baik tentang internal kode
Doc Brown
sumber
21
Jawaban sempurna, juga persis seperti yang dijelaskan dalam buku "Bekerja dengan Kode Legacy"
Altoyr
Saya harus melakukan sesuatu seperti ini sekali. Kumpulkan data keluaran khas dari aplikasi sebelum saya memodifikasinya, lalu periksa versi baru aplikasi saya dengan menjalankan data uji yang sama melaluinya. 30 tahun yang lalu ... Fortran ... Itu semacam pemrosesan gambar / pemetaan hal, jadi saya tidak bisa benar-benar tahu apa yang harus 'dihasilkan' dengan melihatnya atau menulis test case. Dan, saya melakukannya pada tampilan vektor Tektronix (persisten). Pekerjaan pemerintah ... 2 Teletype menggedor di belakangku.
4
Orang mungkin menambahkan, Anda masih bisa menulis tes untuk kode lama setelah fakta. Kemudian Anda dapat mencobanya pada versi refactored Anda, dan jika itu rusak, lakukan pencarian pembelahan dua melalui sejarah komit Anda untuk menemukan titik di mana ia mulai rusak.
CodeMonkey
2
Saya sarankan melakukan satu hal lagi. Saat mengumpulkan data uji, kumpulkan statistik cakupan kode jika memungkinkan. Anda akan tahu seberapa baik data pengujian Anda menggambarkan kode yang dimaksud.
liori
2
@nocomprende, Lucu sekali saya melakukan hal itu dengan kode ilmiah fortran 77 warisan minggu lalu. Tambahkan pencetakan data ascii ke file, atur direktori uji dengan input dan output yang diharapkan, dan test case saya hanyalah perbedaan dari dua set output. Jika mereka tidak cocok dengan karakter untuk karakter, saya merusak sesuatu. Ketika kode sebagian besar adalah dua subrutin yang masing-masing 2-3k LoC, Anda harus memulai suatu tempat.
Godric Seer
1

Alasan penting untuk menulis unit test adalah karena mereka mendokumentasikan komponen API entah bagaimana. Tidak memahami tujuan kode yang sedang diuji benar-benar masalah di sini. Cakupan kode adalah tujuan penting lainnya, sulit untuk dicapai tanpa mengetahui cabang eksekusi yang ada dan bagaimana mereka dipicu.

Namun jika dimungkinkan untuk mengatur ulang keadaan secara bersih (atau membuat objek pengujian baru setiap saat), seseorang dapat menulis tes tipe "trash in-trash out" yang hanya memasukkan sebagian besar input acak ke sistem dan mengamati output.

Tes semacam itu sulit dipertahankan, karena ketika gagal, mungkin rumit untuk mengatakan mengapa dan seberapa serius itu. Cakupan mungkin dipertanyakan. Namun mereka masih jauh lebih baik daripada tidak sama sekali. Ketika pengujian tersebut gagal, pengembang dapat merevisi perubahan terbaru dengan lebih banyak perhatian dan mudah-mudahan menemukan bug di sana.

h22
sumber
1
Setiap jenis info lebih baik daripada terbang buta. Saya biasa mencari bug di program server yang sedang dalam produksi dengan memanggil debugger pada file dump dump (Unix) dan meminta jejak stack. Itu memberi saya nama fungsi di mana kesalahan terjadi. Bahkan tanpa pengetahuan lain (saya tidak tahu cara menggunakan debugger ini) itu membantu dalam apa yang seharusnya menjadi situasi misterius dan tidak dapat diproduksi kembali.