Unit testing - Basis data aplikasi gabungan

15

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.

pengguna1189880
sumber
1
Menarik bahwa jawaban yang secara efektif mengatakan "menulis ulang kode aplikasi Anda" akan dipilih
AD7six

Jawaban:

10

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!

chrisaycock
sumber
1
Dengan DI dan desain aplikasi yang tepat, Anda harus dapat menguji tanpa basis data --- asalkan tiruan yang Anda berikan memberikan mengejek cukup rinci dari database back-end.
Peter K.
4

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.

Tidak mungkin
sumber
2

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 .

Dalam pemrograman berorientasi objek , objek tiruan adalah objek simulasi yang meniru perilaku objek nyata dengan cara yang terkontrol. Seorang programmer biasanya membuat objek tiruan untuk menguji perilaku beberapa objek lain, dengan cara yang sama seperti seorang perancang mobil menggunakan dummy uji tabrakan untuk mensimulasikan perilaku dinamis manusia dalam dampak kendaraan ...

EricSchaefer
sumber
1

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.

knut
sumber
2
Maksud unit test adalah untuk menguji kode Anda secara terpisah. Jika Anda menggunakan sqllite db maka tidak terisolasi. Juga ketidakkonsistenan di antara basis data dapat menyebabkan kesalahan
Tom Squires
0

"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.

AD7six
sumber
Menjelaskan tes unit yang menguji fungsi yang bertindak pada database sebagai tes integrasi cukup menyesatkan @murph.
AD7six
1
Ok, sekarang saya sangat bingung - jika itu melibatkan sebuah database yang bukan oleh sebagian besar definisi unit test karena tidak mandiri. Jika Anda memiliki database maka Anda menjalankan tes di tingkat yang lebih tinggi, yang memiliki ketergantungan yang terlihat pada "menggabungkan" hal-hal. Bagaimanapun ini bukan penjelasan yang jelas di benak saya tentang bagaimana menyelesaikan masalah.
Murph
0

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
0

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, bukan SELECT 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 sehingga getPhoneNumber()akan selalu kembali 555-555-5555atau sesuatu, alih-alih menyentuh basis data.

Izkata
sumber
0

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.

James Anderson
sumber