Ada jawaban untuk pertanyaan tentang bagaimana kelas uji yang terhubung ke database, mis. "Haruskah kelas uji layanan terhubung ..." dan "Pengujian unit - Aplikasi yang digabungkan dengan basis data" .
Jadi, singkatnya mari kita asumsikan Anda memiliki kelas A yang perlu terhubung ke database. Alih-alih membiarkan A benar-benar terhubung, Anda memberikan A dengan antarmuka yang A dapat digunakan untuk terhubung. Untuk pengujian Anda mengimplementasikan antarmuka ini dengan beberapa hal - tanpa menghubungkan tentu saja. Jika kelas B instantiate A harus melewati koneksi database "nyata" ke A. Tapi itu berarti B membuka koneksi database. Itu berarti untuk menguji B Anda menyuntikkan koneksi ke B. Tapi B dipakai di kelas C dan sebagainya.
Jadi pada titik mana saya harus mengatakan "di sini saya mengambil data dari database dan saya tidak akan menulis unit test untuk potongan kode ini"?
Dengan kata lain: Di suatu tempat dalam kode di beberapa kelas saya harus menelepon sqlDB.connect()
atau yang serupa. Bagaimana saya menguji kelas ini?
Dan apakah itu sama dengan kode yang harus berurusan dengan GUI atau sistem file?
Saya ingin melakukan Tes Unit. Jenis tes lain apa pun tidak terkait dengan pertanyaan saya. Saya tahu bahwa saya hanya akan menguji satu kelas dengan itu (saya sangat setuju dengan Anda Kilian). Sekarang, beberapa kelas harus terhubung ke DB. Jika saya ingin menguji kelas ini dan bertanya "Bagaimana saya melakukan ini" banyak yang mengatakan: "Gunakan Injeksi Ketergantungan!" Tapi itu hanya memindahkan masalah ke kelas lain, bukan? Jadi saya bertanya, bagaimana cara menguji kelas yang benar-benar membangun koneksi?
Pertanyaan bonus: Beberapa jawaban di sini bermuara pada "Gunakan benda tiruan!" Apa artinya? Saya mengejek kelas yang bergantung pada kelas yang diuji. Haruskah saya mengejek kelas yang sedang diuji sekarang dan benar-benar menguji tiruannya (yang mendekati gagasan menggunakan Metode Templat, lihat di bawah)?
sumber
Jawaban:
Inti dari tes unit adalah untuk menguji satu kelas (pada kenyataannya, biasanya harus menguji satu metode ).
Ini berarti bahwa ketika Anda menguji kelas
A
, Anda menyuntikkan database uji ke dalamnya - sesuatu yang ditulis sendiri, atau database dalam memori yang cepat, apa pun yang menyelesaikan pekerjaan.Namun, jika Anda menguji kelas
B
, yang merupakan klienA
, maka biasanya Anda mengejek seluruhA
objek dengan sesuatu yang lain, mungkin sesuatu yang melakukan tugasnya dengan cara primitif, yang telah diprogram sebelumnya - tanpa menggunakanA
objek aktual dan tentunya tanpa menggunakan data base (kecualiA
melewati seluruh koneksi basis data kembali ke peneleponnya - tapi itu sangat mengerikan saya tidak ingin memikirkannya). Demikian juga, ketika Anda menulis unit test untuk kelasC
, yang merupakan klienB
, Anda akan mengejek sesuatu yang mengambil peranB
, dan lupakanA
semuanya.Jika Anda tidak melakukan itu, itu bukan lagi tes unit, tetapi tes sistem atau integrasi. Itu juga sangat penting, tetapi ketel ikan yang sama sekali berbeda. Untuk mulai dengan, mereka biasanya lebih banyak upaya untuk mengatur dan menjalankan, itu tidak praktis untuk menuntut melewati mereka sebagai prasyarat untuk check-in, dll.
sumber
Melakukan tes unit terhadap koneksi database sangat normal, dan merupakan praktik yang umum. Sama sekali tidak mungkin untuk membuat
purist
pendekatan di mana segala sesuatu di sistem Anda dapat disuntikkan ketergantungan.Kuncinya di sini adalah untuk menguji terhadap basis data sementara atau hanya menguji, dan memiliki proses memulai paling ringan untuk membangun database pengujian.
Untuk pengujian unit di CakePHP ada hal-hal yang disebut
fixtures
. Jadwal adalah tabel basis data sementara yang dibuat dengan cepat untuk pengujian unit. Fixture memiliki metode kenyamanan untuk membuatnya. Mereka dapat membuat ulang skema dari database produksi di dalam database pengujian, atau Anda dapat menentukan skema menggunakan notasi sederhana.Kunci sukses dengan ini adalah tidak mengimplementasikan database bisnis, tetapi untuk fokus hanya pada aspek kode yang Anda uji. Jika Anda memiliki tes unit yang memverifikasi bahwa model data hanya membaca dokumen yang diterbitkan, maka skema tabel untuk tes itu hanya memiliki bidang yang diperlukan oleh kode itu. Anda tidak perlu menerapkan kembali seluruh basis data manajemen konten hanya untuk menguji kode itu.
Beberapa referensi tambahan.
http://en.wikipedia.org/wiki/Test_fixture
http://phpunit.de/manual/3.7/en/database.html
http://book.cakephp.org/2.0/id/development/testing.html#fixtures
sumber
Ada, di suatu tempat di basis kode Anda, satu baris kode yang melakukan tindakan aktual untuk menghubungkan ke DB jarak jauh. Baris kode ini, 9 kali dalam 10, panggilan ke metode "bawaan" yang disediakan oleh pustaka runtime yang spesifik untuk bahasa dan lingkungan Anda. Karena itu, ini bukan kode "Anda" dan karenanya Anda tidak perlu mengujinya; untuk keperluan pengujian unit, Anda dapat percaya bahwa panggilan metode ini akan bekerja dengan benar. Apa yang Anda bisa, dan harus, masih uji di unit test unit Anda adalah hal-hal seperti memastikan parameter yang akan digunakan untuk panggilan ini adalah apa yang Anda harapkan, seperti memastikan string koneksi sudah benar, atau pernyataan SQL atau nama prosedur tersimpan.
Ini adalah salah satu tujuan di balik pembatasan bahwa tes unit tidak boleh meninggalkan "kotak pasir" runtime dan bergantung pada keadaan eksternal. Ini sebenarnya cukup praktis; tujuan dari tes unit adalah untuk memverifikasi bahwa kode yang Anda tulis (atau akan menulis, dalam TDD) berperilaku seperti yang Anda pikir akan. Kode yang tidak Anda tulis, seperti perpustakaan yang Anda gunakan untuk melakukan operasi basis data Anda, tidak boleh menjadi bagian dari cakupan setiap unit test, karena alasan yang sangat sederhana bahwa Anda tidak menulisnya.
Di suite tes integrasi Anda , pembatasan ini santai. Sekarang kamu bisates desain yang menyentuh database, untuk memastikan bahwa kode yang Anda tulis bermain dengan baik dengan kode yang tidak Anda tulis. Namun, dua suite pengujian ini harus tetap dipisahkan, karena unit test suite Anda lebih efektif semakin cepat dijalankan (sehingga Anda dapat dengan cepat memverifikasi bahwa semua pernyataan yang dibuat oleh pengembang tentang kode mereka masih berlaku), dan hampir secara definisi, tes integrasi lebih lambat oleh urutan besarnya karena ketergantungan ditambahkan pada sumber daya eksternal. Biarkan build-bot menangani menjalankan paket integrasi penuh Anda setiap beberapa jam, menjalankan tes yang mengunci sumber daya eksternal, sehingga pengembang tidak saling menginjak jari kaki dengan menjalankan tes yang sama ini secara lokal. Dan jika bangunannya rusak, lalu apa? Jauh lebih penting ditempatkan pada memastikan build-bot tidak pernah gagal membangun daripada yang seharusnya.
Sekarang, seberapa ketat Anda dapat mematuhinya tergantung pada strategi pasti Anda untuk menghubungkan dan menanyakan database. Dalam banyak kasus di mana Anda harus menggunakan kerangka akses data "tulang kosong", seperti objek SqlConnection dan SqlStatement ADO.NET, seluruh metode yang dikembangkan oleh Anda dapat terdiri dari pemanggilan metode bawaan dan kode lain yang bergantung pada memiliki koneksi basis data, dan yang terbaik yang dapat Anda lakukan dalam situasi ini adalah mengejek seluruh fungsi dan mempercayai suite pengujian integrasi Anda. Ini juga tergantung pada seberapa bersedia Anda merancang kelas Anda untuk memungkinkan baris kode tertentu diganti untuk tujuan pengujian (seperti saran Tobi tentang pola Metode Templat, yang bagus karena memungkinkan "tiruan sebagian")
Jika model ketekunan data Anda bergantung pada kode di lapisan data Anda (seperti pemicu, procs tersimpan, dll) maka tidak ada cara lain untuk menjalankan kode yang Anda sendiri tulis selain mengembangkan tes yang hidup di dalam lapisan data atau melintasi batas antara runtime aplikasi Anda dan DBMS. Seorang purist akan mengatakan pola ini, karena alasan ini, harus dihindari demi sesuatu seperti ORM. Saya tidak berpikir saya akan melangkah sejauh itu; bahkan di zaman query yang terintegrasi dengan bahasa dan operasi ketekunan yang diperiksa oleh kompiler lainnya, saya melihat nilai dalam mengunci basis data hingga hanya operasi yang diekspos melalui prosedur tersimpan, dan tentu saja prosedur tersimpan tersebut harus diverifikasi menggunakan otomatis tes. Tapi, tes semacam itu bukan tes unit . Mereka adalah integrasi tes.
Jika Anda memiliki masalah dengan perbedaan ini, biasanya didasarkan pada kepentingan yang tinggi ditempatkan pada "cakupan kode" lengkap alias "cakupan unit test". Anda ingin memastikan setiap baris kode Anda dicakup oleh tes unit. Sebuah tujuan mulia di wajahnya, tetapi saya katakan omong kosong; bahwa mentalitas cocok untuk anti-pola yang jauh melampaui kasus khusus ini, seperti menulis tes tegas yang mengeksekusi tetapi tidak berolahragakode Anda. Jenis end-run ini semata-mata demi nomor pertanggungan lebih berbahaya daripada melonggarkan cakupan minimum Anda. Jika Anda ingin memastikan bahwa setiap baris basis kode Anda dieksekusi oleh beberapa tes otomatis, maka itu mudah; saat menghitung metrik cakupan kode, sertakan tes integrasi. Anda bahkan dapat melangkah lebih jauh dan mengisolasi tes "Itino" yang disengketakan ini ("Integrasi nama saja"), dan antara unit uji unit Anda dan sub-kategori tes integrasi ini (yang seharusnya masih berjalan cukup cepat) Anda harus mendapatkan darn dekat dengan cakupan penuh.
sumber
Tes unit tidak boleh terhubung ke database. Menurut definisi, mereka harus menguji satu unit kode masing-masing (metode) dalam isolasi total dari sisa sistem Anda. Jika tidak, maka itu bukan tes unit.
Selain semantik, ada banyak alasan mengapa ini bermanfaat:
Tes unit adalah cara untuk memeriksa pekerjaan Anda. Mereka harus menguraikan semua skenario untuk metode yang diberikan, yang biasanya berarti semua jalur yang berbeda melalui metode. Ini adalah spesifikasi yang Anda bangun, mirip dengan pembukuan entri ganda.
Apa yang Anda gambarkan adalah tipe lain dari tes otomatis: tes integrasi. Meskipun mereka juga sangat penting, idealnya Anda akan memiliki lebih sedikit dari mereka. Mereka harus memverifikasi bahwa sekelompok unit saling berintegrasi dengan baik.
Jadi, bagaimana Anda menguji berbagai hal dengan akses database? Semua kode akses data Anda harus berada dalam lapisan tertentu, sehingga kode aplikasi Anda dapat berinteraksi dengan layanan yang dapat diolok-olok alih-alih database yang sebenarnya. Seharusnya tidak peduli apakah layanan tersebut didukung oleh semua jenis database SQL, data uji dalam memori, atau bahkan data layanan web jarak jauh. Itu bukan urusan mereka.
Idealnya (dan ini sangat subjektif), Anda ingin sebagian besar kode Anda dicakup oleh unit test. Ini memberi Anda keyakinan bahwa setiap karya bekerja secara independen. Setelah potongan-potongan dibangun, Anda harus menyatukannya. Contoh - ketika saya hash kata sandi pengguna, saya harus mendapatkan output yang tepat ini.
Katakanlah setiap komponen terdiri dari sekitar 5 kelas - Anda ingin menguji semua titik kegagalan di dalamnya. Ini sama dengan tes yang jauh lebih sedikit hanya untuk memastikan semuanya terhubung dengan benar. Contoh - uji Anda dapat menemukan pengguna dari database yang diberikan nama pengguna / kata sandi.
Akhirnya, Anda ingin beberapa tes penerimaan benar-benar memastikan Anda memenuhi tujuan bisnis. Bahkan ada lebih sedikit lagi; mereka dapat memastikan aplikasi berjalan dan melakukan apa yang dibangun untuk dilakukan. Contoh - mengingat data tes ini, saya harus bisa login.
Pikirkan ketiga jenis tes ini sebagai piramida. Anda memerlukan banyak unit test untuk mendukung semuanya, dan kemudian Anda bekerja dengan cara Anda dari sana.
sumber
The Metode Template Pola mungkin membantu.
Anda membungkus panggilan ke database dalam
protected
metode. Untuk menguji kelas ini Anda benar-benar menguji objek palsu yang mewarisi dari kelas koneksi database nyata dan menimpa metode yang dilindungi.Dengan cara ini panggilan sebenarnya ke database tidak pernah di bawah unit test, itu benar. Tapi ini hanya beberapa baris kode. Dan itu bisa diterima.
sumber
Pengujian dengan data eksternal adalah tes integrasi. Uji unit berarti Anda hanya menguji unit. Sebagian besar dilakukan dengan logika bisnis Anda. Untuk membuat unit kode Anda dapat diuji, Anda harus mengikuti beberapa pedoman, seperti Anda harus membuat unit Anda independen dari bagian lain dari kode Anda. Selama pengujian unit jika Anda membutuhkan data maka Anda harus secara paksa menyuntikkan data tersebut dengan injeksi ketergantungan. Ada beberapa kerangka mengejek dan mematikan di luar sana.
sumber