Saya sarankan untuk mengejek panggilan Anda ke database. Mock pada dasarnya adalah objek yang terlihat seperti objek yang Anda coba panggil metode, dalam arti bahwa mereka memiliki sifat yang sama, metode, dll tersedia untuk pemanggil. Tetapi alih-alih melakukan tindakan apa pun yang diprogram untuk dilakukan ketika metode tertentu dipanggil, metode itu melompati semuanya, dan hanya mengembalikan hasilnya. Hasil itu biasanya ditentukan oleh Anda sebelumnya.
Untuk mengatur objek Anda untuk diolok-olok, Anda mungkin perlu menggunakan semacam inversi dari pola injeksi kontrol / dependensi, seperti dalam pseudo-code berikut:
class Bar
{
private FooDataProvider _dataProvider;
public instantiate(FooDataProvider dataProvider) {
_dataProvider = dataProvider;
}
public getAllFoos() {
// instead of calling Foo.GetAll() here, we are introducing an extra layer of abstraction
return _dataProvider.GetAllFoos();
}
}
class FooDataProvider
{
public Foo[] GetAllFoos() {
return Foo.GetAll();
}
}
Sekarang dalam pengujian unit Anda, Anda membuat tiruan FooDataProvider, yang memungkinkan Anda memanggil metode GetAllFoos tanpa harus benar-benar menekan database.
class BarTests
{
public TestGetAllFoos() {
// here we set up our mock FooDataProvider
mockRepository = MockingFramework.new()
mockFooDataProvider = mockRepository.CreateMockOfType(FooDataProvider);
// create a new array of Foo objects
testFooArray = new Foo[] {Foo.new(), Foo.new(), Foo.new()}
// the next statement will cause testFooArray to be returned every time we call FooDAtaProvider.GetAllFoos,
// instead of calling to the database and returning whatever is in there
// ExpectCallTo and Returns are methods provided by our imaginary mocking framework
ExpectCallTo(mockFooDataProvider.GetAllFoos).Returns(testFooArray)
// now begins our actual unit test
testBar = new Bar(mockFooDataProvider)
baz = testBar.GetAllFoos()
// baz should now equal the testFooArray object we created earlier
Assert.AreEqual(3, baz.length)
}
}
Skenario mengejek yang umum, singkatnya. Tentu saja Anda mungkin masih ingin menguji unit panggilan database aktual Anda juga, yang Anda harus menekan database.
Idealnya, objek Anda harus bodoh. Misalnya, Anda harus memiliki "lapisan akses data", yang akan Anda ajukan permintaan, yang akan mengembalikan objek. Dengan cara ini, Anda dapat membiarkan bagian itu keluar dari unit test Anda, atau mengujinya secara terpisah.
Jika objek Anda tergabung erat dengan lapisan data Anda, sulit untuk melakukan pengujian unit yang tepat. bagian pertama dari unit test, adalah "unit". Semua unit harus dapat diuji secara terpisah.
Dalam proyek c # saya, saya menggunakan NHibernate dengan lapisan data yang sepenuhnya terpisah. Objek saya hidup dalam model domain inti dan diakses dari lapisan aplikasi saya. Lapisan aplikasi berbicara ke lapisan data dan lapisan model domain.
Lapisan aplikasi juga kadang-kadang disebut "Lapisan Bisnis".
Jika Anda menggunakan PHP, buat satu set kelas khusus untuk akses data HANYA . Pastikan objek Anda tidak tahu bagaimana mereka bertahan dan pasang keduanya di kelas aplikasi Anda.
Pilihan lain adalah menggunakan mocking / stubs.
sumber
Cara termudah untuk menguji unit objek dengan akses database menggunakan cakupan transaksi.
Sebagai contoh:
Ini akan mengembalikan keadaan database, pada dasarnya seperti rollback transaksi sehingga Anda dapat menjalankan tes sebanyak yang Anda inginkan tanpa efek samping. Kami telah menggunakan pendekatan ini dengan sukses dalam proyek-proyek besar. Proses pembuatan kami membutuhkan waktu agak lama (15 menit), tetapi tidak mengerikan untuk memiliki 1.800 unit tes. Juga, jika waktu pembangunan menjadi masalah, Anda dapat mengubah proses pembuatan untuk memiliki beberapa bangunan, satu untuk membangun src, yang lain akan menyala setelahnya yang menangani pengujian unit, analisis kode, pengemasan, dll ...
sumber
Saya mungkin bisa memberi Anda pengalaman kami ketika kami mulai melihat unit menguji proses tingkat menengah kami yang mencakup satu ton operasi "logika bisnis" sql.
Kami pertama kali membuat lapisan abstraksi yang memungkinkan kami untuk "memasukkan" koneksi database yang masuk akal (dalam kasus kami, kami hanya mendukung koneksi tipe ODBC tunggal).
Setelah ini di tempat, kami kemudian dapat melakukan sesuatu seperti ini dalam kode kami (kami bekerja di C ++, tapi saya yakin Anda mendapatkan idenya):
GetDatabase (). ExecuteSQL ("INSERT INTO foo (blah, blah)")
Pada waktu normal, GetDatabase () akan mengembalikan objek yang mengumpankan semua sql kami (termasuk kueri), melalui ODBC langsung ke database.
Kami kemudian mulai mencari di dalam memori database - yang terbaik tampaknya SQLite. ( http://www.sqlite.org/index.html ). Ini sangat sederhana untuk diatur dan digunakan, dan memungkinkan kami subkelas dan menimpa GetDatabase () untuk meneruskan sql ke basis data dalam memori yang dibuat dan dihancurkan untuk setiap pengujian yang dilakukan.
Kami masih dalam tahap awal ini, tapi sejauh ini terlihat bagus, namun kami harus memastikan kami membuat tabel apa saja yang diperlukan dan mengisinya dengan data uji - namun kami telah mengurangi beban kerja di sini dengan membuat satu set fungsi pembantu umum yang dapat melakukan banyak hal untuk kita.
Secara keseluruhan, ini sangat membantu proses TDD kami, karena membuat perubahan yang tampaknya tidak berbahaya untuk memperbaiki bug tertentu dapat memiliki dampak yang cukup aneh pada area lain (sulit dideteksi) pada sistem Anda - karena sifat sql / database.
Jelas, pengalaman kami berpusat di sekitar lingkungan pengembangan C ++, namun saya yakin Anda mungkin bisa mendapatkan pekerjaan serupa di bawah PHP / Python.
Semoga ini membantu.
sumber
Anda harus mengejek akses basis data jika Anda ingin menguji unit Anda di kelas. Lagi pula, Anda tidak ingin menguji basis data dalam unit test. Itu akan menjadi tes integrasi.
Abaikan panggilan dan kemudian masukkan tiruan yang baru saja mengembalikan data yang diharapkan. Jika kelas Anda tidak melakukan lebih dari mengeksekusi kueri, bahkan mungkin tidak layak untuk mengujinya, ...
sumber
Buku Pola Tes xUnit menjelaskan beberapa cara untuk menangani kode unit-testing yang mengenai database. Saya setuju dengan orang lain yang mengatakan bahwa Anda tidak ingin melakukan ini karena lambat, tetapi kadang-kadang Anda harus melakukannya, IMO. Mengejek koneksi db untuk menguji hal-hal tingkat tinggi adalah ide yang baik, tetapi periksa buku ini untuk saran tentang hal-hal yang dapat Anda lakukan untuk berinteraksi dengan database yang sebenarnya.
sumber
Opsi yang Anda miliki:
Suntikkan basis data. (Contoh dalam pseudo-Java, tetapi berlaku untuk semua bahasa OO)
sekarang dalam produksi Anda menggunakan database normal dan untuk semua tes Anda cukup menyuntikkan database tiruan yang dapat Anda buat ad hoc.User
bukan tuple{name: "marcin", password: "blah"}
) tulis semua tes Anda dengan objek nyata yang dibuat ad hoc dan tulis satu tes besar yang bergantung pada database yang memastikan konversi ini bekerja dengan baik.Tentu saja pendekatan ini tidak saling eksklusif dan Anda dapat mencampur dan mencocokkannya sesuai kebutuhan.
sumber
Unit yang menguji akses basis data Anda cukup mudah jika proyek Anda memiliki kohesi yang tinggi dan sambungan yang longgar. Dengan cara ini Anda hanya dapat menguji hal-hal yang dilakukan masing-masing kelas tanpa harus menguji semuanya sekaligus.
Misalnya, jika Anda menguji kelas antarmuka pengguna Anda, tes yang Anda tulis hanya mencoba memverifikasi logika di dalam UI yang berfungsi seperti yang diharapkan, bukan logika bisnis atau tindakan basis data di balik fungsi tersebut.
Jika Anda ingin menguji unit akses database aktual Anda sebenarnya akan berakhir dengan lebih banyak tes integrasi, karena Anda akan bergantung pada tumpukan jaringan dan server database Anda, tetapi Anda dapat memverifikasi bahwa kode SQL Anda melakukan apa yang Anda minta. melakukan.
Kekuatan tersembunyi dari pengujian unit bagi saya secara pribadi adalah bahwa hal itu memaksa saya untuk mendesain aplikasi saya dengan cara yang jauh lebih baik daripada saya tanpa mereka. Ini karena itu benar-benar membantu saya melepaskan diri dari mentalitas "fungsi ini harus melakukan segalanya".
Maaf saya tidak punya contoh kode khusus untuk PHP / Python, tetapi jika Anda ingin melihat .NET contoh saya punya posting yang menjelaskan teknik yang saya gunakan untuk melakukan pengujian yang sama.
sumber
Saya biasanya mencoba untuk memecah tes saya antara menguji objek (dan ORM, jika ada) dan menguji db. Saya menguji objek-sisi hal dengan mengejek panggilan akses data sedangkan saya menguji sisi db hal dengan menguji interaksi objek dengan db yang, dalam pengalaman saya, biasanya cukup terbatas.
Dulu saya merasa frustrasi dengan menulis unit test sampai saya mulai mengejek bagian akses data sehingga saya tidak harus membuat test db atau menghasilkan data uji dengan cepat. Dengan mengejek data, Anda dapat menghasilkan semuanya pada saat dijalankan dan pastikan bahwa objek Anda berfungsi dengan baik dengan input yang dikenal.
sumber
Saya tidak pernah melakukan ini dalam PHP dan saya tidak pernah menggunakan Python, tetapi yang ingin Anda lakukan adalah mengejek panggilan ke database. Untuk melakukan itu, Anda dapat mengimplementasikan beberapa IOC apakah alat pihak ke-3 atau Anda mengelolanya sendiri, maka Anda dapat menerapkan beberapa versi palsu dari pemanggil basis data di mana Anda akan mengontrol hasil panggilan palsu itu.
Bentuk sederhana dari IoC dapat dilakukan hanya dengan mengkodekan ke Antarmuka. Ini memerlukan semacam orientasi objek yang terjadi dalam kode Anda sehingga mungkin tidak berlaku untuk apa yang Anda lakukan (saya katakan bahwa karena yang harus saya lakukan hanyalah menyebutkan PHP dan Python)
Semoga bermanfaat, jika tidak ada yang lain Anda punya istilah untuk mencari sekarang.
sumber
Saya setuju dengan akses pasca - basis data pertama harus dilucuti ke lapisan DAO yang mengimplementasikan antarmuka. Kemudian, Anda dapat menguji logika Anda terhadap implementasi rintisan dari lapisan DAO.
sumber
Anda bisa menggunakan kerangka kerja mengejek untuk mengabstraksi mesin basis data. Saya tidak tahu apakah PHP / Python mendapatkan beberapa tetapi untuk bahasa yang diketik (C #, Java dll) ada banyak pilihan
Ini juga tergantung pada bagaimana Anda mendesain kode akses database tersebut, karena beberapa desain lebih mudah untuk diuji unit daripada yang lain seperti posting sebelumnya telah disebutkan.
sumber
Menyiapkan data uji untuk unit test bisa menjadi tantangan.
Ketika datang ke Jawa, jika Anda menggunakan API Musim Semi untuk pengujian unit, Anda dapat mengontrol transaksi pada tingkat unit. Dengan kata lain, Anda dapat menjalankan tes unit yang melibatkan pembaruan / sisipan / penghapusan basis data dan kembalikan perubahan. Di akhir eksekusi, Anda meninggalkan semua yang ada di database seperti sebelum memulai eksekusi. Bagi saya, itu sama baiknya dengan yang bisa didapat.
sumber