Saya mencoba untuk mempraktekkan TDD, dengan menggunakannya untuk mengembangkan yang sederhana seperti Bit Vector. Saya kebetulan menggunakan Swift, tetapi ini adalah pertanyaan bahasa-agnostik.
My BitVector
adalah struct
yang menyimpan satu UInt64
, dan menyajikan API di atasnya yang memungkinkan Anda memperlakukannya seperti koleksi. Detailnya tidak terlalu penting, tetapi cukup sederhana. 57 bit tinggi adalah bit penyimpanan, dan 6 bit lebih rendah adalah bit "hitung", yang memberitahu Anda berapa banyak bit penyimpanan yang benar-benar menyimpan nilai yang terkandung.
Sejauh ini, saya memiliki beberapa kemampuan yang sangat sederhana:
- Inisialisasi yang membangun vektor bit kosong
- Sebuah
count
properti jenisInt
- Sebuah
isEmpty
properti jenisBool
- Operator kesetaraan (
==
). NB: ini adalah operator kesetaraan nilai yang serupa denganObject.equals()
di Jawa, bukan operator kesetaraan referensi seperti==
di Jawa.
Saya mengalami sekelompok ketergantungan siklus:
Tes unit yang menguji penginisialisasi saya perlu memverifikasi bahwa yang baru dibangun
BitVector
. Ini dapat dilakukan dengan salah satu dari 3 cara:- Memeriksa
bv.count == 0
- Memeriksa
bv.isEmpty == true
- Periksa itu
bv == knownEmptyBitVector
Metode 1 mengandalkan
count
, metode 2 bergantung padaisEmpty
(yang bergantung pada itu sendiricount
, jadi tidak ada gunanya menggunakannya), metode 3 bergantung==
. Bagaimanapun, saya tidak dapat menguji inisialisasi saya secara terpisah.- Memeriksa
Tes
count
kebutuhan untuk beroperasi pada sesuatu, yang pasti menguji inisialisasi sayaImplementasi
isEmpty
mengandalkancount
Implementasi
==
mengandalkancount
.
Saya dapat menyelesaikan sebagian masalah ini dengan memperkenalkan API pribadi yang membangun a BitVector
dari pola bit yang ada (sebagai a UInt64
). Ini memungkinkan saya untuk menginisialisasi nilai tanpa menguji inisialisasi lainnya, sehingga saya bisa "booting" dengan cara saya.
Agar unit test saya benar-benar menjadi unit test, saya menemukan diri saya melakukan banyak peretasan, yang menyulitkan prod dan kode pengujian saya secara substansial.
Bagaimana tepatnya Anda mengatasi masalah semacam ini?
sumber
BitVector
adalah ukuran unit yang sangat baik untuk pengujian unit dan segera menyelesaikan masalah Anda bahwa anggota publikBitVector
saling membutuhkan untuk melakukan tes yang bermakna.Jawaban:
Anda terlalu khawatir tentang detail implementasi.
Tidak masalah bahwa dalam implementasi Anda saat ini ,
isEmpty
bergantung padacount
(atau hubungan apa pun yang mungkin Anda miliki): yang harus Anda perhatikan hanyalah antarmuka publik. Misalnya, Anda dapat melakukan tiga tes:count == 0
.isEmpty == true
Ini semua adalah tes yang valid, dan menjadi sangat penting jika Anda pernah memutuskan untuk refactor internal kelas Anda sehingga
isEmpty
memiliki implementasi yang berbeda yang tidak bergantungcount
- selama tes Anda semua masih berlalu, Anda tahu Anda belum mundur apa pun.Hal serupa berlaku untuk poin Anda yang lain - ingatlah untuk menguji antarmuka publik, bukan implementasi internal Anda. Anda mungkin menemukan TDD berguna di sini, karena Anda kemudian akan menulis tes yang Anda butuhkan
isEmpty
sebelum Anda menulis implementasi apa pun untuk itu.sumber
Anda merevisi pemikiran Anda tentang apa itu "unit test".
Objek yang mengelola data yang dapat berubah dalam memori pada dasarnya adalah mesin negara. Jadi setiap use case yang berharga akan, setidaknya, memanggil metode untuk memasukkan informasi ke objek, dan memanggil metode untuk membaca salinan informasi dari objek. Dalam kasus penggunaan yang menarik, Anda juga akan menggunakan metode tambahan yang mengubah struktur data.
Dalam praktiknya, ini sering terlihat seperti
atau
Terminologi "unit test" - yah, ia memiliki sejarah panjang yang tidak terlalu baik.
Kent menulis versi pertama SUnit pada tahun 1994 , pelabuhan ke JUnit adalah pada tahun 1998, draft pertama buku TDD adalah awal tahun 2002. Kebingungan memiliki banyak waktu untuk menyebar.
Gagasan kunci dari tes ini (lebih tepatnya disebut "tes programmer" atau "tes pengembang") adalah bahwa tes diisolasi satu sama lain. Tes tidak membagikan struktur data yang dapat berubah, sehingga dapat dijalankan secara bersamaan. Tidak ada kekhawatiran bahwa tes harus dijalankan dalam urutan tertentu untuk mengukur solusi dengan benar.
Kasus penggunaan utama untuk tes ini adalah bahwa tes tersebut dijalankan oleh programmer antara pengeditan dengan kode sumbernya sendiri. Jika Anda menjalankan protokol refactor merah hijau, RED yang tidak terduga selalu menunjukkan kesalahan dalam edit terakhir Anda; Anda mengembalikan perubahan itu, memverifikasi bahwa tesnya HIJAU, dan coba lagi. Tidak ada banyak keuntungan dalam mencoba berinvestasi dalam desain di mana setiap bug yang mungkin ditangkap hanya dengan satu tes.
Tentu saja, gabungan menggabungkan kesalahan, lalu menemukan bahwa kesalahan tidak lagi sepele. Ada berbagai langkah yang dapat Anda ambil untuk memastikan bahwa kesalahan mudah dilokalisasi. Lihat
sumber
Secara umum (bahkan jika tidak menggunakan TDD) Anda harus berusaha keras untuk menulis tes sebanyak mungkin sambil pura-pura Anda tidak tahu bagaimana itu diterapkan.
Jika Anda benar-benar melakukan TDD itu sudah seharusnya demikian. Tes Anda adalah spesifikasi program yang dapat dieksekusi.
Bagaimana grafik panggilan terlihat di bawah tes tidak relevan, selama tes itu sendiri masuk akal dan terpelihara dengan baik.
Saya pikir masalah Anda adalah pemahaman Anda tentang TDD.
Masalah Anda menurut saya adalah bahwa Anda "mencampur" persona TDD Anda. Ide "test", "code", dan "refactor" Anda beroperasi sepenuhnya secara independen satu sama lain, idealnya. Khususnya, pengkodean dan refactoring personas Anda tidak memiliki kewajiban terhadap pengujian selain untuk membuat / membuatnya tetap hijau.
Tentu, pada prinsipnya, akan lebih baik jika semua tes ortogonal dan independen satu sama lain. Tapi itu bukan masalah dari dua persona TDD Anda yang lain, dan jelas bukan persyaratan keras yang ketat atau bahkan realistis dari tes Anda. Pada dasarnya: Jangan membuang akal sehat Anda tentang kualitas kode untuk mencoba memenuhi persyaratan yang tidak ada yang meminta Anda.
sumber