Apa yang akan menjadi pendekatan terbaik di unit pengujian model yang terintegrasi ke dalam aplikasi yang sangat erat dengan database?
Skenario khusus di sini adalah keranjang belanja - Saya ingin dapat menguji penambahan dan pengambilan barang dari keranjang serta logika penetapan harga, dll. Ini dalam pikiran saya semua memerlukan akses basis data meskipun saya telah membaca beberapa kali bahwa akses basis data harus dihindari.
unit-testing
pengguna1189880
sumber
sumber
Jawaban:
Injeksi ketergantungan adalah salah satu cara menangani hal ini. Anda dapat mengatur database pengujian untuk meniru keranjang belanja, atau Anda bahkan dapat menulis beberapa kode yang "mengkonfirmasi" transaksi pelanggan. Kemudian pada saat runtime, perangkat lunak Anda akan memilih komponen mana yang akan dihubungkan.
Hanya saja, jangan terhubung ke database produksi untuk apa pun selama pengujian!
sumber
Dalam pengujian unit, Anda harus menentukan batas dari apa yang Anda uji. Pengujian unit berbeda dari pengujian integrasi. Jika logika penetapan harga independen dari konten Keranjang, maka Anda mengujinya secara terpisah. Jika ini bukan masalahnya, dan semua modul dipasangkan dengan erat, bangun lingkungan pengujian yang meniru produksi sebanyak yang Anda bisa dan bekerja dengannya. Saya tidak percaya bahwa jalan pintas dan simulasi membantu dalam jangka panjang.
sumber
Model tidak harus bergantung pada DB (konkret). Jika hanya tahu DB abstrak (baca "antarmuka") yang diberikan kepada model maka Anda dapat mengganti DB dengan objek tiruan .
sumber
Saya memiliki masalah yang sama - saya tidak memiliki kemungkinan untuk menjamin DB pengujian saya menjaga nilai-nilai. Jadi di masa depan saya mendapatkan mis. Harga lainnya.
Saya mengekstraksi data yang saya butuhkan menjadi sqlite -DB kecil dan menggunakan DB ini untuk pengujian saya. Test-DB sekarang merupakan bagian dari pengaturan unit-test saya.
sumber
"Best" adalah subyektif, tetapi Anda bisa menggunakan koneksi test db.
Gunakan fixture untuk memuat beberapa data uji (contoh produk yang akan dibeli) dan kemudian tulis kasus uji untuk kelas / fungsi yang ingin Anda uji.
sumber
Saya membangun sebuah plugin untuk Symfony 1.4 (PHP) untuk mengatasi masalah ini (antara lain). Ini dimodelkan setelah cara kerangka uji Django beroperasi (Python) : kerangka kerja membangun dan mengisi basis data pengujian terpisah sebelum setiap pengujian dimulai, dan itu menghancurkan basis data pengujian setelah setiap pengujian selesai.
Saya punya beberapa kekhawatiran tentang strategi ini, baik dari segi kinerja (jika skema tidak berubah, mengapa tidak menghapus data daripada membangun kembali seluruh struktur?) Dan kenyamanan (kadang-kadang saya ingin memeriksa database setelah gagal ujian, jadi jangan hancurkan tanpa pandang bulu!), jadi saya mengambil pendekatan yang sedikit berbeda.
Sebelum pengujian pertama berjalan, basis data dihancurkan dan dibangun kembali, jika ada perubahan model sejak pengujian terakhir. Sebelum setiap pengujian berikutnya berjalan, data dalam database dihapus, tetapi struktur tidak dibangun kembali (meskipun pembangunan kembali manual dapat dipicu dari pengujian jika perlu).
Dengan memuat perlengkapan data secara selektif di setiap tes, seseorang dapat menciptakan lingkungan yang tepat untuk tes itu tanpa mengganggu tes berikutnya. File fixture juga dapat digunakan kembali, yang membuat tugas ini jauh lebih sulit (meskipun itu masih bagian favorit saya dari tes menulis!).
Dalam kedua kerangka kerja pengujian, adaptor basis data dikonfigurasikan untuk menggunakan koneksi uji alih-alih koneksi "produksi" untuk mencegah pelaksanaan pengujian merusak data yang ada.
sumber
Saya katakan, langsung saja gunakan perlengkapan untuk memuat data sebelumnya. Begitulah cara kerja unit pengujian tampaknya berfungsi secara umum, saat menguji manipulasi data.
Tetapi jika Anda benar-benar ingin menghindari harus terhubung ke database dalam bentuk apa pun dan pergi dengan definisi yang terlalu ketat bahwa tes unit tidak menyentuh apa pun di luar kode, lihat objek mengejek - itu mungkin memberi Anda ide.
Sebagai contoh, alih-alih menjatuhkan SQL secara langsung dalam kode di mana Anda membutuhkannya, miliki cara untuk memanggil metode yang hanya melakukan apa yang SQL lakukan. Gunakan
Person.getPhoneNumber()
, misalnya, bukanSELECT phone_number FROM person WHERE id = <foo>
. Tidak hanya lebih bersih dan lebih mudah untuk dipahami sekilas, tetapi selama pengujian Anda dapat mengejek objek Person sehinggagetPhoneNumber()
akan selalu kembali555-555-5555
atau sesuatu, alih-alih menyentuh basis data.sumber
Ini cukup mudah dilakukan dengan junit jika agak panjang lebar.
"Pengaturan" harus mendefinisikan dan mengisi satu set tabel sementara.
Anda kemudian dapat melakukan tes unit untuk semua pembaruan, menyisipkan, menghapus fungsionalitas.
Untuk setiap pengujian Anda memanggil metode pembaruan Anda kemudian jalankan beberapa SQL untuk memverifikasi hasil yang diharapkan.
Pada fase "teardown" Anda menjatuhkan semua tabel.
Dengan cara ini Anda selalu menjalankan tes yang sama pada data awal yang sama. Jika Anda menyimpan tabel di antara tes yang akhirnya "tercemar" oleh tes yang gagal, juga, tes "sisipkan" yang konsisten hampir tidak mungkin dilakukan karena Anda harus terus menciptakan kunci baru pada setiap tes.
sumber