Apakah tes untuk pengembangan yang digerakkan oleh tes (TDD) selalu merupakan unit-tes?

41

Saya memahami pengembangan yang digerakkan oleh tes sejauh ini sehingga Anda hanya diperbolehkan menulis kode produktif ketika Anda memiliki tes unit yang gagal (merah). Berdasarkan hal ini saya memiliki pertanyaan apakah pendekatan yang digerakkan oleh tes juga dapat diterapkan pada bentuk tes lainnya.

pengguna1364368
sumber
6
Tidak jarang menggunakan lebih dari satu level berbeda dari merah / hijau / refactor yang bersarang di dalam satu sama lain. Misalnya, Anda dapat mengikuti merah / hijau / refactor saat menulis tes penerimaan / perilaku, di mana fase 'hijau' dari tes penerimaan itu sendiri berisi beberapa iterasi merah / hijau / refactor dari unit test.
Sean Burton
1
Judul tidak cocok dengan konten pertanyaan. Judul "apakah tes selalu unit-tes " (jawaban: tidak, mungkin ada jenis tes lain selain unit-tes), isinya bertanya "Anda harus menulis tes terlebih dahulu?".
AnoE
@AnoE Kalimat pertama dari konten hanyalah pernyataan pengantar. Kalimat detik tidak menanyakan apakah tes harus ditulis terlebih dahulu, tetapi apakah pendekatan TDD dapat digunakan untuk metode pengujian selain TDD.
user1364368
@ user1364368, jangan ragu untuk merumuskan kembali sedikit pertanyaan, setidaknya saya bingung tentang apa maksud Anda pada bacaan pertama, dan pertanyaan pilihan-tertinggi, sementara menangani kedua kalimat Anda juga dimulai dengan jelas dengan yang pertama.
AnoE
@AnoE Saya mengubah awal kalimat kedua untuk memperjelas apa pertanyaan sebenarnya.
user1364368

Jawaban:

27

Yang Anda butuhkan dari TDD adalah Anda menulis tes yang gagal, lalu memodifikasi kode Anda agar lulus.

Biasanya "tes unit" kecil dan cepat dan menguji beberapa bagian dari kode Anda secara terpisah. Karena mereka cepat, itu membuat loop merah / hijau / refactor juga cepat. Namun, mereka hanya menderita bagian pengujian dalam isolasi. Jadi Anda perlu tes lain juga (integrasi, penerimaan dll). Ini masih merupakan praktik yang baik untuk mengikuti prinsip yang sama: menulis tes gagal, lalu memodifikasi kode untuk membuatnya berfungsi. Perlu diketahui bahwa mereka biasanya lebih lambat, sehingga dapat mempengaruhi waktu siklus merah / hijau / refactor.

David Arno
sumber
59

Siklus refactor merah hijau dibangun di atas satu prinsip yang sangat kuat:

Hanya uji kepercayaan yang Anda lihat lulus dan gagal.

Ya itu berfungsi dengan tes integrasi otomatis juga. Juga tes manual. Heck, itu bekerja pada penguji aki mobil. Inilah cara Anda menguji tes.

Beberapa orang menganggap unit test mencakup hal terkecil yang dapat diuji. Beberapa orang memikirkan sesuatu yang cepat untuk diuji. TDD lebih dari sekedar siklus refactor merah hijau tetapi bagian itu memiliki serangkaian tes yang sangat spesifik: Ini bukan tes yang idealnya Anda jalankan sekali sebelum mengirimkan kumpulan perubahan. Ini adalah tes yang akan Anda jalankan setiap kali Anda membuat perubahan. Bagi saya, itu adalah unit test Anda.

candied_orange
sumber
1
Yang juga merupakan salah satu alasan mengapa pengujian negatif penting ketika menguji bahwa suatu kesalahan terjadi: Anda ingin memastikan bahwa segala sesuatu yang lain akan berfungsi, sehingga memiliki dua pengujian (satu menghasilkan kesalahan yang diharapkan tepat, yang lain tidak menghasilkan kesalahan) di sebelah satu sama lain membantu meningkatkan kepercayaan bahwa di masa depan keadaan merah / hijau ini akan berlanjut.
Matthieu M.
12

Namun, saya bertanya-tanya apakah pendekatan yang digerakkan oleh tes juga dapat diterapkan pada bentuk tes lainnya.

Ya, dan pendekatan terkenal yang melakukan ini adalah pengembangan yang didorong oleh Perilaku . Tes yang dihasilkan dari spesifikasi formal dalam BDD mungkin disebut "tes unit", tetapi biasanya tidak setingkat seperti pada TDD nyata, mereka mungkin akan lebih cocok dengan istilah "tes penerimaan".

Doc Brown
sumber
8

Saya memahami pengembangan yang digerakkan oleh tes sejauh ini sehingga Anda hanya diperbolehkan menulis kode produktif ketika Anda memiliki tes unit yang gagal (merah).

Tidak. Anda hanya diperbolehkan menulis kode sesederhana mungkin untuk mengubah pesan tes. Itu tidak mengatakan apa-apa tentang tes seperti apa.

Bahkan, Anda mungkin akan mulai dengan menulis tes penerimaan gagal (merah) untuk kriteria penerimaan, lebih tepatnya, Anda menulis tes penerimaan paling sederhana yang mungkin gagal; setelah itu Anda menjalankan tes, melihatnya gagal, dan memverifikasi bahwa itu gagal karena alasan yang tepat. Kemudian Anda menulis tes fungsional yang gagal untuk sepotong fungsionalitas kriteria penerimaan itu, sekali lagi, Anda menulis tes fungsional paling sederhana yang mungkin gagal, menjalankannya, menontonnya gagal, dan memverifikasi bahwa itu gagal karena alasan yang tepat. Kemudian Anda menulis tes unit gagal, tes unit paling sederhana yang mungkin gagal, jalankan melihatnya gagal, verifikasi bahwa itu gagal karena alasan yang tepat.

Sekarang , Anda menulis kode produksi paling sederhana yang dapat mengubah pesan kesalahan. Jalankan pengujian lagi, verifikasi bahwa pesan kesalahan telah berubah, bahwa itu berubah ke arah yang benar, dan bahwa kode itu mengubah pesan untuk alasan yang benar. (Idealnya, pesan kesalahan harus hilang sekarang, dan tes harus lulus, tetapi lebih sering daripada tidak, lebih baik untuk mengambil langkah kecil mengubah pesan daripada mencoba untuk mendapatkan tes untuk lulus dalam sekali jalan - itulah alasannya mengapa pengembang kerangka kerja uji coba menghabiskan begitu banyak upaya untuk pesan kesalahan mereka!)

Setelah tes unit berhasil, Anda memperbaiki kode produksi Anda di bawah perlindungan pengujian Anda. (Perhatikan bahwa saat ini, tes penerimaan dan tes fungsional masih gagal, tetapi tidak apa-apa, karena Anda hanya refactoring unit individual yang dicakup oleh tes unit.)

Sekarang Anda membuat tes unit berikutnya dan ulangi di atas, sampai tes fungsional juga berlalu. Di bawah perlindungan uji fungsional, kini Anda dapat melakukan refactor di beberapa unit.

Siklus tengah ini sekarang berulang hingga tes penerimaan berlalu, pada titik mana Anda sekarang dapat melakukan refactor di seluruh sistem.

Sekarang, Anda memilih kriteria penerimaan berikutnya dan siklus luar dimulai lagi.

Kent Beck, "penemu" dari TDD (dia tidak suka istilah "penemu", katanya orang telah melakukan ini selama ini, dia hanya memberi nama dan menulis buku tentang itu) menggunakan analogi dari fotografi dan menyebutnya "memperbesar dan memperkecil".

Catatan: Anda tidak selalu membutuhkan tiga tingkat tes. Mungkin, terkadang Anda membutuhkan lebih banyak. Lebih sering, Anda membutuhkan lebih sedikit. Jika kepingan fungsionalitas Anda kecil, dan uji fungsional Anda cepat, maka Anda bisa bertahan tanpa (atau dengan tes unit lebih sedikit). Seringkali, Anda hanya perlu tes penerimaan dan tes unit. Atau, kriteria penerimaan Anda sangat halus sehingga tes penerimaan Anda adalah tes fungsional.

Kent Beck mengatakan bahwa jika dia memiliki tes fungsional yang cepat, kecil, dan fokus, dia pertama-tama akan menulis unit test, biarkan unit test mengemudikan kode, kemudian hapus (beberapa) unit test lagi yang mencakup kode yang juga tercakup oleh tes fungsional cepat. Ingat: kode uji juga kode yang perlu dipertahankan dan dire-refored, semakin sedikit, semakin baik!

Namun, saya bertanya-tanya apakah pendekatan yang digerakkan oleh tes juga dapat diterapkan pada bentuk tes lainnya.

Anda tidak benar-benar menerapkan TDD pada tes. Anda menerapkannya pada seluruh proses pengembangan Anda. Itulah yang dimaksud dengan "didorong" dari Test- Driven -Development: semua pengembangan Anda didorong oleh tes. Tes tidak hanya mengarahkan kode yang Anda tulis, tetapi juga mengarahkan kode apa yang akan ditulis, kode mana yang akan ditulis selanjutnya. Mereka menggerakkan desain Anda. Mereka memberi tahu Anda ketika Anda selesai. Mereka memberi tahu Anda apa yang harus dikerjakan selanjutnya. Mereka memberi tahu Anda tentang cacat desain dalam kode Anda (ketika tes sulit untuk menulis).

Keith Braithwaite telah menciptakan latihan yang dia sebut TDD As If You Meant It . Ini terdiri dari seperangkat aturan (berdasarkan Tiga Aturan TDD Paman Bob Martin , tetapi jauh lebih ketat) yang harus Anda ikuti dengan ketat dan yang dirancang untuk mengarahkan Anda untuk menerapkan TDD dengan lebih ketat. Ini bekerja paling baik dengan pemrograman pasangan (sehingga pasangan Anda dapat memastikan Anda tidak melanggar aturan) dan seorang instruktur.

Aturannya adalah:

  1. Tulis persis satu tes baru, tes terkecil yang bisa Anda lakukan yang mengarah pada solusi
  2. Lihat itu gagal; kegagalan kompilasi dihitung sebagai kegagalan
  3. Buat tes dari (1) lulus dengan menulis kode implementasi paling tidak yang Anda bisa dalam metode pengujian .
  4. Refactor untuk menghilangkan duplikasi, dan jika tidak diperlukan untuk meningkatkan desain. Ketat menggunakan gerakan ini:
    1. Anda menginginkan metode baru — tunggu hingga waktu refactoring, lalu… buat metode baru (non-tes) dengan melakukan salah satu dari ini, dan tidak dengan cara lain:
      • lebih disukai: lakukan Extract Method pada kode implementasi yang dibuat sesuai dengan (3) untuk membuat metode baru di kelas tes, atau
      • jika Anda harus: memindahkan kode implementasi sesuai (3) ke metode implementasi yang ada
    2. Anda ingin kelas baru — tunggu sampai waktu refactoring, lalu ... buat kelas non-tes untuk memberikan tujuan untuk Metode Pindah dan tanpa alasan lain
    3. mengisi kelas implementasi dengan metode dengan melakukan Metode Pindah, dan tidak ada cara lain

Aturan-aturan ini dimaksudkan untuk melakukan TDD. Mereka tidak dimaksudkan untuk benar-benar melakukan TDD dalam produksi (meskipun tidak ada yang menghentikan Anda untuk mencobanya). Mereka bisa merasa frustasi karena kadang-kadang akan tampak seolah-olah Anda membuat ribuan langkah kecil mungil tanpa membuat kemajuan nyata.

Jörg W Mittag
sumber
2

TDD sama sekali tidak terbatas pada apa yang oleh komunitas pengujian Perangkat Lunak tradisional disebut "unit testing". Kesalahpahaman yang sangat umum ini adalah akibat kelebihan muatan Kent Beck yang tidak menguntungkan dari istilah "unit" ketika menggambarkan praktiknya tentang TDD. Yang dia maksud dengan "unit test" adalah tes yang berjalan secara terpisah. Itu tidak tergantung pada tes lain. Setiap tes harus mengatur keadaan yang dibutuhkan dan melakukan pembersihan ketika selesai. Dalam pengertian ini bahwa unit test dalam arti TDD adalah unit. Itu mandiri. Itu dapat berjalan dengan sendirinya atau dapat dijalankan bersama dengan tes unit lain dalam urutan apa pun.

Referensi : "Pengembangan Didorong oleh Contoh", oleh Kent Beck

Kent Beck menjelaskan apa yang dia maksud dengan “unit test” di Bab 32 - Menguasai TDD

Jason Desrosiers
sumber
1

Saya belum membaca buku-buku tentang itu, saya juga tidak sepenuhnya mengikuti praktik TDD "standar" sepanjang waktu, tetapi dalam pikiran saya poin utama dari filosofi TDD, yang saya sepenuhnya setujui, adalah bahwa Anda harus mendefinisikan kesuksesan terlebih dahulu . Ini penting di setiap tingkat desain, dari "Apa tujuan proyek ini?" untuk "Bagaimana seharusnya input dan output dari metode kecil ini?"

Ada banyak cara untuk melakukan definisi kesuksesan ini. Yang berguna, terutama untuk metode tingkat rendah dengan banyak kasus tepi, adalah menulis tes dalam kode. Untuk beberapa tingkat abstraksi, akan bermanfaat jika hanya menuliskan catatan singkat tentang tujuan modul atau apa pun, atau bahkan hanya memeriksa diri sendiri secara mental (atau bertanya pada rekan kerja) untuk memastikan semuanya masuk akal dan ada dalam tempat yang logis. Kadang-kadang membantu untuk menjelaskan tes integrasi dalam kode (dan tentu saja yang membantu seseorang untuk mengotomatiskannya), dan kadang-kadang membantu hanya dengan menentukan rencana pengujian cepat yang masuk akal yang dapat Anda gunakan untuk memastikan semua sistem bekerja sama dengan cara Anda mengharapkan.

Tetapi terlepas dari teknik atau alat khusus yang Anda gunakan, dalam pikiran saya hal utama untuk mengambil dari filosofi TDD adalah bahwa mendefinisikan kesuksesan terjadi terlebih dahulu. Kalau tidak, Anda melempar panah dan melukis bullseye di mana pun itu mendarat.


sumber
1

Dalam pembicaraan Test-Driven Development: Ini bukan apa yang kami maksud Steve Freeman menunjukkan slide berikut dari gambaran besar TDD (lihat gambar di bawah ini). Ini termasuk langkah "Tulis tes ujung-ke-ujung yang gagal" yang diikuti oleh "Tulis unit-gagal". (Klik untuk memperbesar, ini ada di kanan atas)

Jadi tidak dalam TDD, tes tidak selalu merupakan unit-tes.

Dan ya Anda bisa (dan mungkin harus) mulai dengan tes end-to-end tingkat tinggi yang gagal sebelum Anda menulis unit-test pertama Anda. Tes ini menjelaskan perilaku yang ingin Anda capai. Ini menghasilkan cakupan pada lebih banyak level piramida uji . Adrian Sutton menjelaskan pengalaman LMAX yang menunjukkan bahwa tes ujung ke ujung dapat memainkan peran besar dan berharga .

masukkan deskripsi gambar di sini

Niels van Reijmersdal
sumber
-1

Tidak, itu tidak dapat diterapkan pada jenis tes lain, karena alasan praktis sederhana: jenis tes lain terlalu lama untuk dijalankan.

Siklus TDD yang umum adalah: tes gagal tulis, implementasikan, kode refactor. Langkah-langkah di antaranya adalah membangun dan melaksanakan tes, dan ini harus cepat kilat. Jika tidak, maka orang akan mulai melewatkan langkah-langkah, dan kemudian Anda tidak melakukan TDD lagi.

BЈовић
sumber
1
Ini tidak benar: tergantung pada program dan tes (dan bahasa), tes integrasi ujung-ke-ujung dapat dengan mudah berjalan dalam waktu kurang dari 3 detik. Sangat mungkin untuk menjalankan rangkaian uji ujung ke ujung dalam waktu yang sangat singkat, bahkan, jika dirancang dengan baik. Jadi "tidak bisa" cukup kuat.
Jonathan Cast
@cast Saya tidak pernah melihat hal lain yang begitu cepat. Tes fungsional saya pada proyek saya sebelumnya membutuhkan waktu 30 detik, dan itu cepat. Integrasi bahkan lebih lama. Dalam kasus saya, tidak ada hal lain yang masuk akal. Juga, tes unit adalah yang tercepat dari semua jenis tes - karena itu masuk akal untuk menggunakannya.
BЈовић