Saya benar-benar berjuang untuk menulis unit test yang efektif untuk proyek Django besar. Saya memiliki cakupan tes yang cukup baik, tetapi saya menyadari bahwa tes yang saya tulis jelas merupakan tes integrasi / penerimaan, bukan tes unit sama sekali, dan saya memiliki bagian penting dari aplikasi saya yang tidak diuji secara efektif. Saya ingin memperbaiki ASAP ini.
Inilah masalah saya. Skema saya sangat relasional, dan sangat berorientasi waktu, memberikan objek model saya kopling internal yang tinggi dan banyak keadaan. Banyak model metode saya kueri berdasarkan interval waktu, dan saya punya banyak hal auto_now_add
terjadi di bidang timestamped. Jadi ambil metode yang terlihat seperti ini misalnya:
def summary(self, startTime=None, endTime=None):
# ... logic to assign a proper start and end time
# if none was provided, probably using datetime.now()
objects = self.related_model_set.manager_method.filter(...)
return sum(object.key_method(startTime, endTime) for object in objects)
Bagaimana satu pendekatan menguji sesuatu seperti ini?
Di sinilah saya sejauh ini. Terjadi pada saya bahwa tujuan pengujian unit harus diberikan beberapa perilaku mengejek by key_method
pada argumennya, apakah summary
benar penyaringan / agregasi untuk menghasilkan hasil yang benar?
Mengolok-olok datetime.now () cukup mudah, tetapi bagaimana saya bisa mengejek perilaku lainnya?
- Saya bisa menggunakan perlengkapan, tapi saya sudah mendengar pro dan kontra menggunakan perlengkapan untuk membangun data saya (rawatan yang buruk menjadi con yang membuat saya pulang).
- Saya juga bisa mengatur data saya melalui ORM, tapi itu bisa membatasi, karena dengan begitu saya harus membuat objek terkait juga. Dan ORM tidak membiarkan Anda mengacaukan
auto_now_add
bidang secara manual. - Mengejek ORM adalah pilihan lain, tetapi tidak hanya sulit untuk mengejek metode ORM yang bersarang, tetapi logika dalam kode ORM akan diejek dari tes, dan mengejek tampaknya membuat tes benar-benar tergantung pada internal dan dependensi dari tes fungsi
Kacang yang paling sulit retak tampaknya adalah fungsi-fungsi seperti ini, yang terdapat pada beberapa lapisan model dan fungsi tingkat yang lebih rendah dan sangat tergantung pada waktu, walaupun fungsi-fungsi ini mungkin tidak terlalu rumit. Masalah saya secara keseluruhan adalah bahwa tidak peduli bagaimana saya mengirisnya, pengujian saya terlihat jauh lebih kompleks daripada fungsi yang mereka uji.
sumber
Jawaban:
Saya akan pergi ke depan dan mendaftarkan jawaban untuk apa yang saya dapatkan sejauh ini.
Hipotesis saya adalah bahwa untuk suatu fungsi dengan kopling dalam dan keadaan, kenyataannya adalah bahwa itu hanya akan mengambil banyak garis untuk mengontrol konteks luarnya.
Begini kira-kira kasus pengujian saya, dengan mengandalkan pustaka Mock standar:
datetime
dan menumbangkanauto_now_add
waktu agar sesuai dengan garis waktu tetap desain saya. Saya pikir ORM tidak mengizinkan ini, tetapi berfungsi dengan baik.from datetime import datetime
sehingga saya bisa menambaldatetime.now()
hanya dalam fungsi itu (jika saya mengejek seluruhdatetime
kelas, ORM cocok).object.key_method()
, dengan fungsionalitas sederhana namun terdefinisi dengan baik yang bergantung pada argumen. Saya ingin ini bergantung pada argumen, karena kalau tidak saya mungkin tidak tahu apakah logika dari fungsi-di-tes berfungsi. Dalam kasus saya, itu hanya mengembalikan jumlah detik antarastartTime
danendTime
. Saya menambalnya dengan membungkusnya dalam lambda dan menambal langsungobject.key_method()
menggunakannew_callable
kwarg daripatch
.summary
dengan argumen yang berbeda untuk memeriksa kesetaraan dengan hasil yang dihitung dengan tangan yang dihitung untuk perilaku mock yang diberikan.key_method
Tak perlu dikatakan, ini jauh lebih lama dan lebih rumit daripada fungsi itu sendiri. Itu tergantung pada DB, dan tidak benar-benar terasa seperti unit test. Tetapi juga cukup dipisahkan dari internal fungsi - hanya tanda tangan dan dependensinya. Jadi saya pikir itu mungkin benar-benar menjadi unit test.
Dalam aplikasi saya, fungsi ini sangat penting, dan dapat direactoring untuk mengoptimalkan kinerjanya. Jadi saya pikir masalahnya tidak sia-sia, meskipun kompleksitas. Tapi saya masih terbuka untuk ide-ide yang lebih baik tentang cara mendekati ini. Semua bagian dari perjalanan panjang saya menuju gaya pengembangan yang lebih digerakkan oleh tes ...
sumber