7 days of WordPress plugins, themes & templates - for free!* Unlimited asset downloads! Start 7-Day Free Trial
Advertisement
  1. Code
  2. PHP

Mari kita TDD aplikasi sederhana di PHP

Scroll to top
Read Time: 16 mins
This post is part of a series called Test-Driven PHP.
Automatic Testing for TDD with PHP
Deciphering Testing Jargon

Indonesian (Bahasa Indonesia) translation by Ari Gustiawan (you can also view the original English article)

Dalam tutorial ini, saya akan menyajikan sebuah contoh end-to-end aplikasi sederhana - dibuat secara ketat dengan TDD di PHP. Saya akan memandu Anda langkah demi langkah, satu per satu waktu, sambil menjelaskan keputusan saya untuk menyelesaikan tugas. Contoh erat mengikuti aturan TDD: menulis tes, menulis kode, refactor.


Langkah 1 - pengenalan TDD & PHPUnit

Test Driven Development (TDD)

TDD adalah "test-first" teknik untuk mengembangkan dan desain perangkat lunak. Hal ini hampir selalu digunakan dalam agile team, menjadi salah satu tool pengembangan perangkat lunak agile. TDD pertama kali didefinisikan dan memperkenalkan kepada community profesional oleh Kent Beck pada tahun 2002. Sejak itu, telah menjadi teknik yang diterima - dan direkomendasikan - dalam pemrograman sehari-hari.

TDD memiliki tiga Peraturan inti:

  1. Anda tidak diperbolehkan untuk menulis kode produksi, jika tidak ada tes gagal untuk menjamin itu.
  2. Anda tidak diperbolehkan untuk menulis lebih dari unit test daripada benar-benar diperlukan untuk membuatnya gagal. Tidak kompilasi / menjalankan gagal.
  3. Anda tidak diperbolehkan untuk menulis kode produksi lebih daripada benar-benar diperlukan untuk membuat tes gagal berhasil.

PHPUnit

PHPUnit adalah tool yang memungkinkan programmer PHP untuk melakukan unit testing, dan praktek test-driven development. Ini adalah komplit unit testing framework dengan mocking support. Meskipun ada beberapa alternatif pilihan, PHPUnit adalah yang paling banyak digunakan dan paling lengkap solusi untuk PHP hari ini.

Untuk menginstal PHPUnit, Anda dapat mengikuti bersama dengan tutorial sebelumnya dalam sesi "TDD di PHP" kita, atau Anda dapat menggunakan PEAR, seperti yang dijelaskan dalam dokumentasi resmi:

  • menjadi akar atau menggunakan sudo
  • Pastikan Anda memiliki PEAR terbaru: pear upgrade PEAR
  • mengaktifkan auto penemuan: pear config-set auto_discover 1
  • menginstal PHPUnit: pear install pear.phpunit.de/PHPUnit

Informasi lebih lanjut dan petunjuk untuk menginstal tambahan PHPUnit modul dapat ditemukan dalam dokumentasi resmi.

Beberapa distribusi Linux menawarkan phpunit sebagai sebuah paket Installation, meskipun saya selalu merekomendasikan pemasangan, melalui PEAR, memastikan bahwa versi paling baru dan up-to-date diinstal dan digunakan.

NetBeans & PHPUnit

Jika Anda penggemar NetBeans, Anda bisa mengkonfigurasinya untuk bekerja dengan PHPUnit dengan mengikuti langkah berikut:

  • Pergi ke NetBeans' konfigurasi (Tools / Options)
  • Pilih PHP / Unit Testing
  • Cek entri "PHPUnit Script" entri point menjadi valid PHPUnit executable Jika tidak, NetBeans akan memberitahu Anda ini, jadi jika Anda tidak melihat pemberitahuan merah pada halaman, Anda sudah siap. Jika tidak, cari PHPUnit exceutable pada sistem Anda dan masukkan path di bidang masukan. Untuk sistem Linux, path ini biasanya adalah /usr/bin/phpunit.

Jika Anda tidak menggunakan IDE yang tidak support unit testing, Anda selalu dapat menjalankan tes Anda langsung dari konsol:


Langkah 2 - masalah untuk dipecahkan

Tim kami ini bertugas dengan pelaksanaan fitur "kata pembungkus".

Mari kita asumsikan bahwa kita adalah bagian dari sebuah perusahaan besar, yang memiliki sebuah aplikasi canggih untuk mengembangkan dan maintain. Tim kami ini bertugas dengan pelaksanaan fitur "word wrap". Klien kami tidak ingin melihat horisontal scroll bar, dan keluar pekerjaan untuk mematuhi.

Dalam hal ini, kita perlu membuat sebuah class yang mampu memformat agak sewenang-wenang teks yang diberikan sebagai masukan. Hasilnya harus menjadi kata yang dibungkus di sejumlah karakter tertentu. Aturan word wrapping harus mengikuti perilaku aplikasi sehari-hari lainnya, seperti editor teks, web halaman teks area, dll. Klien kami tidak mengerti semua aturan word wrapping, tetapi mereka tahu mereka menginginkannya, dan mereka tahu itu harus bekerja dengan cara yang sama yang mereka alami dalam aplikasi lain.


Langkah 3 - perencanaan

TDD membantu Anda mencapai desain yang lebih baik, tetapi tidak menghilangkan kebutuhan untuk desain muka dan berpikir.

Salah satu hal yang banyak programmer lupa, setelah mereka mulai TDD, adalah untuk berpikir dan merencanakan terlebih dahulu. TDD membantu Anda mencapai desain yang lebih baik sebagian besar waktu, dengan sedikit kode dan diverifikasi fungsi, tetapi tidak menghilangkan kebutuhan untuk desain muka dan pemikiran manusia.

Setiap kali Anda perlu untuk memecahkan masalah, Anda harus menyisihkan waktu untuk berpikir tentang hal itu, membayangkan sedikit desain - tidak banyak - tapi cukup untuk Anda mulai. Ini bagian dari pekerjaan juga membantu Anda untuk membayangkan dan menebak mungkin skenario untuk logika aplikasi.

Mari kita berpikir tentang aturan-aturan dasar untuk word wrap fitur Saya kira beberapa teks un dibungkus akan diberikan kepada kita. Kita akan mengetahui jumlah karakter per baris dan kami akan menginginkannya untuk dibungkus. Jadi, hal pertama yang datang ke pikiran saya adalah bahwa, jika teks memiliki lebih banyak karakter daripada jumlah dalam satu baris, kita harus menambahkan baris baru bukan karakter ruang terakhir yang masih di garis.

Oke, yang akan meringkas perilaku dari sistem, tetapi hal ini terlalu rumit untuk di tes. Sebagai contoh, bagaimana ketika satu kata lebih dari jumlah karakter yang diperbolehkan pada baris? Hmmm... ini terlihat seperti tepi kasus; kami tidak bisa ganti spasi dengan baris baru karena kita memiliki ada spasi pada baris. Kita harus memaksa membungkus kata , secara efektif memisahkan menjadi dua.

Ide-ide ini harusnya cukup jelas ke titik bahwa kita dapat memulai pemrograman. Kita akan membutuhkan sebuah proyek dan class. Mari kita menyebutnya Wrapper.


Langkah 4 - memulai proyek dan menciptakan tes pertama

Mari kita membuat proyek kami. Harus ada folder utama untuk source class, dan Tests/ folder, tentu saja, untuk tes.

Berkas pertama yang kita akan menciptakan adalah tes dalam folder Tests. Semua tes nanti kami akan terkandung dalam folder ini, jadi saya akan tidak menentukan secara eksplisit lagi dalam tutorial ini. Nama class eksperimen sesuatu deskriptif, tetapi sederhana. WrapperTest akan lakukan untuk sekarang; ujian pertama kami terlihat seperti ini:

Ingat! Kami tidak diperbolehkan untuk menulis kode produksi apapun sebelum tesnya gagal - bahkan Deklarasi class! Itulah mengapa saya menulis tes sederhana pertama di atas, disebut canCreateAWrapper. Beberapa orang menganggap langkah ini tidak berguna, tapi aku menganggap itu sebagai kesempatan bagus untuk berpikir tentang class kami akan membuat. Kita perlu class? harus disebut apa? Harus itu static?

Ketika Anda menjalankan tes di atas, Anda akan menerima pesan kesalahan Fatal, seperti berikut:

Yikes! Kita harus melakukan sesuatu tentang hal itu. Membuat Wrapper class kosong di folder utama proyek.

Thats it. Jika Anda menjalankan tes lagi, akan sukses. Selamat atas pengujian pertama!


Langkah 5 - Real test pertama

Jadi kami memiliki proyek yang mengatur siap dijalankan; Sekarang kita perlu untuk berpikir tentang real test pertama kami.

Apa yang akan menjadi yang paling sederhana... paling bodoh... tes paling dasar yang akan membuat kode produksi kami saat ini gagal? Yah, hal pertama yang datang ke pikiran adalah "Berikan sebuah kata yang cukup singkat, dan mengharapkan hasil menjadi tidak berubah." Ini terdengar dapat dilakukan; Mari kita menulis tes.

Terlihat tampak cukup rumit. Apa artinya "MaxChars" dalam nama fungsi? 5 itu apa dalam metode wrap merujuk?

Saya pikir sesuatu yang tidak cukup di sini. Tidak ada tes sederhana yang dapat kita jalankan? Ya, pasti ada! Bagaimana jika kita membungkus... apa-apa - string kosong? Kedengarannya baik. Menghapus test rumit di atas, dan, sebagai gantinya, tambahkan satu baru, sederhana, ditunjukkan di bawah ini:

Ini jauh lebih baik. Nama tes mudah dimengerti, kita memiliki string tidak ada magic atau angka, dan kebanyakan dari semua, itu gagal!

Seperti yang Anda dapat amati, saya menghapus test pertama kami. Tidak ada gunanya untuk secara eksplisit memeriksa jika sebuah objek dapat diinisialisasi, ketika tes lainnya juga membutuhkannya. Ini normal. Dengan waktu, Anda akan menemukan bahwa menghapus tes adalah hal yang umum. Tes, terutama unit test, harus uijalankan dengan cepat - benar-benar cepat... dan sering - sangat sering. Mengingat ini, menghilangkan redundansi dalam tes ini penting. Bayangkan bahwa Anda menjalankan ribuan tes setiap kali Anda Simpan project. Itu harus tidak lebih dari beberapa menit, maksimum, bagi mereka untuk berjalan. Jadi, jangan takut untuk menghapus tes, jika diperlukan.

Mendapatkan kembali ke kode produksi kami, mari kita membuat tes itu sukses:

Di atas, kami telah menambahkan benar-benar tidak ada kode yang lebih dari diperlukan untuk membuat tes sukses.


Langkah 6 - menekan

Sekarang, untuk tes gagal berikutnya:

Kegagalan pesan:

Dan kode yang membuatnya sukses:

Wow! Itu mudah, bukan?

Sementara kita berada di hijau, mengamati bahwa kode tes kita dapat mulai membusuk. Kita perlu refactor beberapa hal. Ingat: selalu refactor ketika tes and sukses; ini adalah satu-satunya cara bahwa Anda bisa yakin bahwa Anda telah direfractor dengan benar.

Pertama, mari kita menghapus duplikasi inisialisasi objek wrapper. Kita dapat melakukan ini hanya sekali dalam metode setUp(), dan menggunakannya untuk tes kedua.

Metode setup akan berjalan sebelum setiap tes baru.

Selanjutnya, ada beberapa bit ambigu dalam tes kedua. Apa itu 'word'? Apa itu '5'? Mari kita membuat jelas sehingga programmer berikutnya yang membaca tes ini tidak harus menebak.

Tidak pernah lupa bahwa tes Anda juga dokumentasi kode Anda paling update-to-date.

Programmer lain harus mampu membaca tes dengan mudah karena mereka akan membaca dokumentasi.

Sekarang, membaca pernyataan ini lagi. bukankan dibacanya menjadi lebih baik? Tentu saja itu. Jangan takut terhadap nama-nama variabel yang panjang untuk tes Anda; Auto-completion adalah teman Anda! Hal ini lebih baik menjadi sebagai deskriptif mungkin.

Sekarang, untuk tes gagal berikutnya:

Dan kode yang membuatnya sukses:

Itu adalah kode yang jelas untuk membuat kami tes terakhir sukses. Tapi hati-hati - ini juga kode yang membuat tidak sukses ujian pertama kami!

Kami memiliki dua pilihan untuk memperbaiki masalah ini:

  • memodifikasi kode - membuat parameter kedua opsional
  • memodifikasi tes pertama - dan membuat panggilan kode dengan parameter

Jika Anda memilih pilihan pertama, membuat parameter opsional, yang akan hadir sedikit masalah dengan kode saat ini. Parameter opsional juga diinisialisasi dengan nilai default. Apa yang bisa dengan nilai tersebut? Nol mungkin terdengar logis, tapi itu akan berarti menulis kode hanya untuk mengobati kasus khusus itu. Menetapkan jumlah yang sangat besar, sehingga pertama if statement tidak akan mengakibatkan benar dapat menjadi solusi lain. Tapi, apa nomor itu? Itu 10? Apakah 10000? Apakah 10000000? Kita tidak bisa mengatakan.

Mengingat semua ini, saya hanya akan memodifikasi tes pertama:

Sekali lagi, Semua hijau. Kita sekarang dapat beralih ke tes berikutnya. Mari kita pastikan bahwa, jika kita memiliki sebuah kata yang sangat panjang, itu akan menyelesaikan beberapa baris.

Ini jelas gagal, karena kode produksi aktual kita membungkus hanya sekali.

Anda dapat mencium while loop datang? Nah, pikirkan lagi. Apakah while loop sederhana kode yang akan membuat tes sukses?

Menurut 'Transformasi prioritas' (oleh Robert C. Martin), hal ini tidak. Rekursi selalu lebih sederhana daripada sebuah loop dan jauh lebih dapat diuji.

Dapatkah Anda bahkan melihat perubahan? Itu sederhana. Semua yang kami lakukan adalah, bukan menggabungkan dengan sisa string, kita menggabungkan dengan nilai kembali memanggil diri mereka sendiri dengan sisa string. Sempurna!


Langkah 7 - hanya dua kata

Tes sederhana berikutnya? Apa tentang dua kata bisa dibungkus, ketika ada spasi di ujung baris.

Itu sesuai dengan baik. Namun, solusi yang mungkin akan mendapatkan sedikit trickier saat ini.

Pada awalnya, Anda mungkin merujuk kepada str_replace() untuk menyingkirkan ruang dan masukkan baris baru. Tidak; jalan yang mengarah ke jalan buntu.

Pilihan kedua paling jelas adalah if statement. Sesuatu seperti ini:

Namun, yang memasuki lingkaran tak berujung, yang akan menyebabkan tes untuk kesalahan keluar.

Saat ini, kita perlu memikirkan! Masalahnya adalah bahwa ujian pertama kami memiliki teks dengan panjang nol. Juga, strpos() mengembalikan false ketika tidak dapat menemukan string. Membandingkan false dengan nol... adalah? adalah true. Ini buruk bagi kita karena loop akan menjadi tak infinite. Solusinya? Mari kita mengubah kondisi pertama. Mencari spasi dan membandingkan posisinya dengan panjang baris, mari kita sebaliknya mencoba untuk secara langsung mengambil karakter pada posisi yang ditunjukkan oleh panjang baris. Kami akan melakukan substr() hanya satu karakter yang panjang, mulai dari tempat yang tepat dalam teks.

Tapi, bagaimana jika ruang tidak tepat di akhir baris?

Hmm... kita harus merevisi kondisi kami lagi. Saya berpikir bahwa kita akan, setelah semua, perlu bahwa pencarian untuk posisi ruang karakter.

Wow! Itu benar-benar bekerja. Kami pindah kondisi pertama dalam kedua sehingga kita menghindari loop tak terbatas, dan kami menambahkan pencarian untuk ruang. Namun, tampaknya agak jelek. Kondisi bersarang? Yuck. Saatnya untuk beberapa refactoring.

Itu lebih baik lebih baik.


Langkah 8 - bagaimana dengan beberapa kata?

Tidak ada hal buruk yang bisa terjadi sebagai hasil dari tes menulis.

Tes sederhana berikutnya akan memiliki tiga kata pembungkus pada tiga baris. Tapi tesnya sukses. Anda harus menulis tes ketika Anda tahu itu akan sukses? Sebagian besar waktu, tidak. Tapi, jika Anda memiliki keraguan, atau Anda dapat membayangkan jelas perubahan kode yang akan membuat tes baru gagal dan yang lain sukses, kemudian menulis itu! Tidak ada hal buruk bisa terjadi sebagai hasil dari tes yang ditulis. Juga, mempertimbangkan bahwa tes Anda adalah dokumentasi Anda. Jika ujian Anda mewakili bagian penting dari logika Anda, kemudian menulis itu!

Lebih lanjut, fakta pengujian kami datang dengan sukses adalah indikasi bahwa kita semakin dekat dengan solusi. Jelas, ketika Anda memiliki algoritma bekerja, tes yang kami menulis akan sukses.

Sekarang - tiga kata pada dua baris dengan baris akhir dalam kata terakhir; Sekarang, itu gagal.

Aku hampir mengharapkan satu ini untuk bekerja. Ketika kami menyelidiki kesalahan, kita mendapatkan:

Yap. Kita harus bungkus ruang paling kanan dalam baris.

Hanya mengganti strpos() dengan strrpos() di dalam if statement kedua.


Langkah 9 - Tes gagal lainnya? Edge kasus-kasus?

Hal semakin rumit. Hal ini cukup sulit untuk menemukan tes gagal... atau tes, hal ini, yang belum ditulis.

Ini adalah indikasi bahwa kita cukup dekat dengan solusi akhir. Tapi, Hei, aku hanya berpikir untuk tes yang akan gagal!

Tapi, aku salah. itu sukses. Hmm... apa kita selesai? Tunggu! Bagaimana tentang yang satu ini?

Gagal! Sangat baik. Ketika baris memiliki panjang yang sama sebagai kata, kami ingin baris kedua untuk tidak memulai dengan spasi.

Ada beberapa solusi. Kami dapat memperkenalkan if statement laiinya untuk memeriksa spasi awal. Yang akan cocok dengan sisa conditional yang kita ciptakan. Tapi, tidak ada solusi yang sederhana? Bagaimana jika kita hanya trim() teks?

Kita coba


Langkah 10 - kita selesai

Pada titik ini, aku tidak menciptakan tes gagal untuk ditulis. Kita harus dilakukan! Kami sekarang telah digunakan TDD untuk membangun sederhana, tapi berguna, six-line algoritma.

Beberapa kata-kata henti dan "selesai." Jika Anda menggunakan TDD, Anda memaksa diri Anda untuk berpikir tentang segala macam situasi. Anda kemudian menulis tes untuk situasi tersebut, dan dalam proses, mulai memahami masalahnya jauh lebih baik. Biasanya, proses ini hasil dalam pengetahuan yang mendalam tentang algoritma. Jika Anda tidak bisa memikirkan apa pun tes gagal untuk ditulis, apakah ini berarti bahwa algoritma sempurna? Tidak perlu, kecuali ada seperangkat standar aturan. TDD tidak menjamin kode menjadi sedikit bug; ini hanya membantu Anda menulis kode yang lebih baik yang dapat lebih baik dipahami dan dimodifikasi.

Bahkan lebih baik, jika Anda menemukan bug, itu adalah bahwa jauh lebih mudah untuk menulis sebuah tes yang mereproduksi bug. Dengan cara ini, Anda dapat memastikan bahwa bug tidak pernah terjadi lagi - karena Anda telah diuji untuk itu!


Catatan akhir

Anda mungkin berpendapat bahwa proses ini adalah tidak secara teknis "TDD." Dan kau benar! Contoh ini lebih tepat untuk berapa banyak pemrogram sehari-hari bekerja. Jika Anda ingin sebuah contoh yang benar "TDD sebagai Anda berarti itu", silakan tinggalkan komentar di bawah ini, dan saya akan berencana untuk menulis satu di lain waktu.

Terima kasih untuk sudah membaca!

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.