Cara TDD agar hasil yang benar dikembalikan


12

Saya memulai proyek baru, dan berusaha sangat keras untuk menggunakan TDD untuk menggerakkan desain. Saya sudah mendorong selama bertahun-tahun, dan akhirnya mendapat persetujuan untuk menghabiskan waktu ekstra pada proyek ini untuk menggunakannya sementara saya belajar bagaimana melakukannya dengan benar.

Ini adalah modul baru, untuk mengikat ke sistem yang ada. Saat ini, semua akses data terjadi melalui layanan web, yang sebagian besar hanyalah pembungkus tipis atas prosedur yang tersimpan dalam basis data.

Salah satu persyaratan adalah bahwa untuk toko tertentu, saya mengembalikan semua Pesanan Pembelian yang dianggap valid untuk aplikasi ini. PO dianggap valid jika tanggal pengiriman jatuh dengan kisaran tertentu dari tanggal pembukaan toko (ini untuk toko baru).

Sekarang, saya tidak bisa memasukkan logika ini dalam kode aplikasi, karena saya tidak akan mengembalikan satu juta PO hanya untuk mendapatkan selusin yang berlaku untuk dapat diterapkan ke toko ini mengingat kendala di atas.

Saya berpikir, saya bisa meneruskan rentang tanggal ke proc GetValidPOs, dan meminta mereka menggunakan nilai-nilai itu untuk mengembalikan PO yang valid. Tetapi, bagaimana jika kita menambahkan persyaratan lain untuk apa yang dianggap sebagai PO yang valid?

Dan bagaimana cara menguji ini dan memverifikasinya tetap berfungsi? Kami tidak menggunakan ORM, dan itu tidak mungkin terjadi. Dan saya tidak bisa memanggil DB dalam pengujian saya.

Aku terjebak.

Pikiran saya yang lain, adalah memiliki beberapa ejekan yang mengembalikan data yang valid, yang lain yang mengembalikan beberapa data buruk, dan membuat repositori lokal melempar pengecualian jika data buruk terjadi, dan menguji bahwa pengecualian dilemparkan jika data yang tidak valid dikembalikan oleh GetValidPOs proc (atau tiruan yang digunakan dalam pengujian).

Apakah ini masuk akal? Atau ada cara yang lebih baik?

UPDATE: Sepertinya saya bisa menggunakan EF. Sekarang saya hanya perlu mencari cara untuk menggunakannya, dan membuatnya dapat diuji, sementara masih bisa mengandalkan prosedur yang tersimpan, dan kesulitan memiliki data yang tersebar di beberapa database.


Karena penasaran, mengapa Anda tidak bisa memilih hanya PO yang valid dengan pernyataan SQL sederhana? (Pertanyaan atau jawaban ini tidak menyiratkan solusi.)
scarfridge

Jawaban:


7

Ini adalah kelemahan utama dari prosedur tersimpan di usia TDD. Mereka memiliki beberapa keuntungan nyata, bahkan sekarang, tetapi menurut definisi setiap tes yang menggunakan proc yang disimpan bukanlah tes unit; ini adalah tes integrasi terbaik.

Solusi yang biasa, dengan asumsi arsitektur tidak dapat berubah untuk menggunakan ORM sebagai gantinya, adalah tidak menempatkan tes ini di unit test suite; sebagai gantinya, letakkan tes dalam suite integrasi. Anda masih dapat menjalankan tes kapan pun Anda ingin memverifikasi itu berfungsi, tetapi karena biaya yang melekat dalam menyiapkan tes (menginisialisasi DB dengan data tes yang tepat) tinggi dan menyentuh sumber daya, agen unit-test build-bot Anda mungkin tidak memiliki akses ke, seharusnya tidak berada di unit test suite.

Anda masih dapat menguji kode unit yang membutuhkan data, dengan mengabstraksi apa pun yang tidak dapat Anda uji unit (kelas ADO.NET) menjadi kelas DAO yang dapat Anda tiru. Anda kemudian dapat memverifikasi bahwa panggilan yang diharapkan dilakukan dengan menggunakan kode dan mereproduksi perilaku dunia nyata (seperti tidak menemukan hasil) yang memungkinkan pengujian berbagai kasus penggunaan. Namun, pengaturan aktual dari SqlCommand untuk memanggil proc yang disimpan cukup banyak hal terakhir yang Anda bisa uji unit, dengan memutuskan pembuatan perintah dari eksekusi perintah dan mengejek pelaksana perintah. Jika ini kedengarannya seperti pemisahan yang banyak dari keprihatinan, bisa jadi itu; ingat, "tidak ada masalah yang tidak dapat diselesaikan dengan lapisan tipuan lainnya, kecuali karena memiliki terlalu banyak lapisan tipuan". Pada titik tertentu Anda harus mengatakan "cukup; Saya tidak bisa menguji unit ini, kami

Pilihan lain:

  • Uji proc yang disimpan menggunakan instance DBMS "berumur pendek" seperti SQLite. Biasanya lebih mudah untuk melakukan ini ketika menggunakan ORM, tetapi tes kemudian dapat dilakukan "di-memori" (atau dengan file database yang telah ditetapkan termasuk dengan test suite). Masih bukan unit test, tetapi dapat dijalankan dengan tingkat isolasi yang tinggi (DBMS adalah bagian dari proses yang sedang berjalan, dan bukan sesuatu yang Anda hubungkan ke jarak jauh yang mungkin berada di tengah-tengah test suite yang saling bertentangan). Kelemahannya adalah bahwa perubahan pada proc yang disimpan dapat terjadi dalam produksi tanpa tes yang mencerminkan perubahan, jadi Anda harus disiplin tentang memastikan perubahan itu pertama kali dilakukan dalam lingkungan pengujian.

  • Pertimbangkan untuk meningkatkan ke ORM. ORM dengan penyedia Linq (hampir semua yang umum digunakan memilikinya) akan memungkinkan Anda untuk mendefinisikan kueri sebagai pernyataan Linq; pernyataan itu kemudian dapat diberikan ke Repositori yang diolok-olok yang memiliki kumpulan data uji dalam memori untuk digunakan. Dengan demikian Anda dapat memverifikasi kueri dengan benar tanpa menyentuh DB (Anda masih harus menjalankan kueri di lingkungan integrasi, untuk menguji bahwa penyedia Linq dapat dengan benar mencerna kueri).


2
-1 karena TDD! = Pengujian unit. Baik-baik saja untuk memasukkan tes tingkat integrasi ketika melakukan TDD.
Steven A. Lowe

Unit testing adalah subset dari pengembangan yang digerakkan oleh test. Dalam pengembangan yang digerakkan oleh tes Anda akan membuat kerangka berjalan dari sistem Anda dan kemudian menjalankan unit, integrasi dan tes fungsional pada sistem itu. Tes integrasi, unit, atau penerimaan gagal, Anda membuatnya lulus dan menulis tes lebih lanjut.
CodeART

1
Saya mengerti semua itu, kalian berdua. Di mana saya mengatakan bahwa itu harus menjadi tes integrasi berarti Anda tidak dapat melakukannya? Maksud saya adalah bahwa prosedur tersimpan tidak dapat diuji secara terpisah, yang merupakan sesuatu yang ingin Anda lakukan untuk sebanyak mungkin basis kode Anda. Menguji SPs sebaliknya membutuhkan tes integrasi yang lebih kompleks dan berjalan lebih lama; sementara mereka masih lebih baik daripada pengujian manual, rangkaian uji integrasi dapat memakan waktu berjam-jam untuk berjalan dan dapat memiliki efek yang merugikan pada upaya CI.
KeithS

Pengujian SP sering juga membutuhkan kumpulan data spesifik dalam database pengujian; kode untuk mendapatkan database dalam keadaan yang tepat untuk mencapai hasil yang diharapkan sangat sering lebih banyak LoC dan beberapa kali lebih lama berjalan daripada kode yang sebenarnya Anda jalankan. Ini semakin memperumit kompleksitas waktu dari test suite, dan seringkali pengaturan harus diulang untuk setiap tes individu (dan mungkin harus ada beberapa untuk setiap SP, untuk menguji bahwa setiap persyaratan fungsional dari permintaan dalam terpenuhi).
KeithS

Prosedur tersimpan dapat diuji secara terpisah. Bagaimana lagi mereka divalidasi? Untuk Transact SQL ada tSQLt ( tsqlt.org )
kevin cline

4

Saran saya adalah membagi dan menaklukkan . Lupakan database dan kegigihan untuk saat ini dan berkonsentrasilah pada pengujian implementasi palsu dari repositori atau objek akses data Anda.

Sekarang, saya tidak bisa memasukkan logika ini dalam kode aplikasi, karena saya tidak akan mengembalikan satu juta PO hanya untuk mendapatkan selusin yang berlaku untuk dapat diterapkan ke toko ini mengingat kendala di atas.

Saya akan mengejek repositori yang mengembalikan pesanan pembelian. Buat tiruan dengan dua puluh pesanan pembelian aneh.

Saya berpikir, saya bisa meneruskan rentang tanggal ke proc GetValidPOs, dan meminta mereka menggunakan nilai-nilai itu untuk mengembalikan PO yang valid. Tetapi, bagaimana jika kita menambahkan persyaratan lain untuk apa yang dianggap sebagai PO yang valid?

Stub panggilan ke GetValidPOs sehingga panggilan tiruan Anda, bukan prosedur database.

Dan bagaimana cara menguji ini dan memverifikasinya tetap berfungsi? Kami tidak menggunakan ORM, dan itu tidak mungkin terjadi. Dan saya tidak bisa memanggil DB dalam pengujian saya.

Anda memerlukan unit-test untuk memastikan data yang benar dikembalikan dari tiruan.

Anda juga memerlukan tes integrasi untuk memastikan data yang benar dikembalikan dari database. Tes integrasi akan memerlukan beberapa konfigurasi dan pembersihan. Misalnya, sebelum menjalankan tes integrasi, seed database Anda dengan menjalankan skrip. Verifikasi bahwa skrip Anda telah berfungsi. Permintaan database dengan memanggil prosedur tersimpan Anda. Pastikan hasil Anda benar. Bersihkan database.

Pikiran saya yang lain, adalah memiliki beberapa ejekan yang mengembalikan data yang valid, yang lain yang mengembalikan beberapa data buruk, dan membuat repositori lokal melempar pengecualian jika data buruk terjadi, dan menguji bahwa pengecualian dilemparkan jika data yang tidak valid dikembalikan oleh GetValidPOs proc (atau tiruan yang digunakan dalam pengujian).

Seperti yang sudah saya katakan, Anda membutuhkan tiruan yang mengembalikan setidaknya beberapa data yang dapat Anda query.

Saat Anda meminta data, Anda ingin memastikan bahwa sistem Anda dapat menangani pengecualian dengan baik. Karenanya, Anda mengejek perilaku sehingga melempar pengecualian dalam skenario tertentu. Anda kemudian menulis tes untuk memastikan bahwa sistem Anda dapat menangani pengecualian ini dengan anggun.


Itulah yang saya coba lakukan. Hanya mengalami kesulitan menulis implementasi nyata yang akan bekerja sama dengan mock, karena akses data kami tidak kondusif untuk menggunakan ORM. Mayoritas data yang saya butuhkan ada di beberapa sistem, dan seharusnya diakses melalui layanan web ... bahkan ketika memperbarui.
CaffGeek

0

Seperti halnya pengujian unit Java atau Javascript berarti menulis pengujian unit menggunakan bahasa Java untuk java, dan pengujian unit fungsi Javascript dengan Javascript, menulis tes otomatis untuk mengarahkan Anda menulis prosedur tersimpan berarti perpustakaan tes unit yang Anda cari didasarkan pada penyimpanan Prosedur.

Dengan kata lain, gunakan prosedur tersimpan untuk menguji prosedur tersimpan karena:

  • karena Anda berkembang dalam bahasa prosedur, Anda harus memiliki keterampilan untuk menulis tes dalam bahasa prosedur
  • tes tertulis dalam bahasa prosedur Anda akan meningkatkan keterampilan Anda pada bahasa prosedur yang pada gilirannya akan membantu pengembangan produk Anda
  • Anda akan memiliki akses langsung ke semua alat yang disediakan DB Anda dan Anda dapat menggunakan alat-alat itu juga membuat tes unit Anda sesederhana mungkin
  • unit test yang disimpan dalam DB yang sama dengan prosedur yang mereka uji akan cepat (hal yang paling dekat dengan unit test seperti kecepatan) karena Anda tidak melewati batas sistem

Sama seperti TDD dalam bahasa OO, Anda ingin pengujian unit Anda hanya mengatur satu atau dua baris data untuk menguji apa yang diperlukan untuk prosedur (minimalisme, hanya memiliki apa yang dibutuhkan tes sederhana Anda). Hasil dari ini adalah Anda akan memiliki beberapa tes unit sederhana untuk setiap prosedur tersimpan. Tes sederhana ini akan lebih mudah dipertahankan daripada memiliki tes rumit yang bergantung pada set data besar yang tidak mudah memetakan kembali apa yang sebenarnya dibutuhkan tes.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.