Bagaimana menyebarkan pengujian unit django pada banyak file?


126
  • Saya memiliki aplikasi python-django
  • Saya menggunakan kerangka pengujian unit
  • Tes disusun dalam file "tests.py" di direktori modul
  • Saya menjalankan tes melalui ./manage.py test app

Sekarang..

  • The tests.pyfile mendapatkan agak besar / kompleks / berantakan
  • Saya ingin memecah tests.pymenjadi koleksi tes yang lebih kecil ...

Bagaimana?

Jawaban:


47

Perilaku telah berubah dalam Django 1.6, jadi tidak perlu lagi membuat paket. Beri nama file Anda test*.py.

Dari dokumentasi Django 1.7

Saat Anda menjalankan pengujian, perilaku default utilitas pengujian adalah menemukan semua kasus pengujian (yaitu, subkelas unittest.TestCase) dalam file apa pun yang namanya dimulai dengan pengujian, secara otomatis membuat rangkaian pengujian dari kasus pengujian tersebut, dan jalankan suite itu.

Dari dokumentasi Django 1.6 ,

Penemuan pengujian didasarkan pada penemuan pengujian built-in modul yang paling unik. Secara default, ini akan menemukan tes dalam file apa pun bernama "test * .py" di bawah direktori kerja saat ini.

Perilaku sebelumnya, dari dokumentasi Django 1.5 :

Saat Anda menjalankan pengujian, perilaku default dari utilitas pengujian adalah menemukan semua kasus pengujian (yaitu, subkelas unittest.TestCase) di models.py dan tests.py, secara otomatis membuat rangkaian pengujian dari kasus pengujian tersebut, dan jalankan suite itu.

Ada cara kedua untuk mendefinisikan rangkaian pengujian untuk sebuah modul: jika Anda mendefinisikan sebuah fungsi yang disebut suite () baik dalam models.py atau test.py, runner percobaan Django akan menggunakan fungsi itu untuk membangun rangkaian percobaan untuk modul itu. Ini mengikuti organisasi yang disarankan untuk pengujian unit. Lihat dokumentasi Python untuk detail lebih lanjut tentang cara membuat rangkaian pengujian yang kompleks.


4
Dalam django 2.6 itu tidak benar-benar menemukan apa-apa…
LtWorf

2
Saat ini menggunakan Django 1.10, saya ingin meletakkan semua test*.pyberkas saya dalam sebuah folder yang dipanggil testsuntuk menjaga folder tetap bersih - ini dimungkinkan, tetapi Anda harus menjalankan ./manage.py test app.testsdan semua impor relatif perlu naik satu tingkat ( from .modelsmenjadi from ..models).
Scott Stevens

123

Perhatikan bahwa pendekatan ini tidak lagi berlaku dari Django 1.6, lihat posting ini .

Anda bisa membuat testsfolder dengan ___init___.pyinside (sehingga menjadi satu paket). Kemudian Anda menambahkan file split test .py Anda di sana dan mengimpor semuanya ___init___.py.

Ie: Gantikan test.pyfile dengan modul yang terlihat dan berfungsi seperti file:

Buat testsDirektori di bawah aplikasi yang dimaksud

aplikasi
app \ models.py
app \ views.py
app \ tes
app \ tests \ __ init__.py
app \ tests \ bananas.py
app \ tests \ apples.py

Impor submodul ke app\tests\__init__.py:

from bananas import *
from apples import *

Sekarang Anda dapat menggunakan ./manage.py seolah-olah semuanya ada dalam satu file:

./manage.py test app.some_test_in_bananas

1
Doh. Maksud Anda membuat modul 'tes' di bawah aplikasi yang saya uji; bukan aplikasi baru yang disebut tes. Aku mengerti sekarang. Mengagumkan. Terima kasih!
John Mee

@ John: Saya tidak dapat mengenali jawaban saya lagi! :-) Tetapi Anda sepenuhnya benar bahwa itu terlalu samar, meskipun benar - contoh Anda membuatnya jelas, bertentangan dengan kata-kata asli saya.
Tomasz Zieliński

2
@ Tomasz .. Kata-kata Anda masih ada - utuh sepenuhnya. Saya hanya menyempurnakannya sedikit karena Anda menempatkan saya di jalur yang benar.
John Mee

@ John: Saya tidak marah sama sekali jika itu yang Anda maksud :) Sungguh lucu melihat jawaban saya sendiri dalam bentuk yang sedikit berbeda
Tomasz Zieliński

4
@jMyles, jika yang Anda maksud dengan "runner pengujian django biasa" python manage.py test myappmaka sebenarnya jawaban ini bekerja dengan baik. (baru saja mencobanya)
Kirk Woll

27

Jawaban Tomasz benar. Namun, mungkin membosankan untuk memastikan bahwa impor __init__.pysesuai dengan struktur file Anda.

Untuk secara otomatis mendeteksi semua tes di folder Anda dapat menambahkan ini di __init__.py:

import unittest

def suite():   
    return unittest.TestLoader().discover("appname.tests", pattern="*.py")

Ini akan memungkinkan Anda untuk menjalankan ./manage.py test appnametetapi tidak akan menangani pengujian tertentu yang sedang berjalan. Untuk melakukannya, Anda dapat menggunakan kode ini (juga di __init__.py):

import pkgutil
import unittest

for loader, module_name, is_pkg in pkgutil.walk_packages(__path__):
    module = loader.find_module(module_name).load_module(module_name)
    for name in dir(module):
        obj = getattr(module, name)
        if isinstance(obj, type) and issubclass(obj, unittest.case.TestCase):
            exec ('%s = obj' % obj.__name__)

Sekarang Anda dapat menjalankan semua pengujian melalui manage.py test appatau pengujian tertentu melaluimanage.py test app.TestApples


Di mana Anda menempatkan potongan kedua?
rh0dium

Kedua bagian masuk__init__.py
Bryce Drennan

Perhatikan bahwa jika salah satu nama paket pengujian Anda sama dengan nama modul tingkat atas yang diimpor selama pengujian dijalankan, cuplikan pkgutil akan menyebabkan pengimporan gagal karena pengujian ditambahkan sebagai sys.modules[packagename]. Solusi cepat adalah untuk delsemua yang menyebabkan masalah setelah di atas. (Atau Anda dapat mengganti nama folder Anda;))
Paul Fenney

Ini bagus, tetapi saya mengalami kesalahan di mana, ketika menjalankan tes level aplikasi ( python manage.py test appName) bit kedua dari kode akan memunculkan kesalahan yang menyatakan bahwa __path__itu tidak tersedia. Saya menghindarinya dengan membungkus potongan kedua dalam sebuah if '__path__' in locals():cek, yang berhasil. Terima kasih atas jawabannya!
alukach

1
+1 ini juga memastikan bahwa file init mematuhi standar pengkodean umum, yaitu tidak memiliki * atau impor yang tidak digunakan
Martin B.

13

Buat saja struktur direktori Anda seperti ini:

myapp/
    __init__.py
    tests/
        __init__.py
        test_one.py
        test_two.py
        ...
    ...

Dan python manage.py test myappakan bekerja seperti yang diharapkan.



2

Tidak perlu membuat kode apa pun di init. Cukup buat subdirektori di aplikasi Anda. Hanya persyaratan untuk tidak menyebutnya tes * Sebagai contoh

app/
app/__init_.py
app/serializers.py
app/testing/
app/testing/__init__.py
app/testing/tests_serializers.py

1
Mengapa Anda tidak bisa menyebutnya sebagai sesuatu yang dimulai dengan "tes"?
Serp C

Saya menggunakan jawaban ini dengan Django 1.11.4. Alasan untuk menggunakannya: (1) File "app / testing / __ init__.py" tetap kosong dan (2) Perintah tetap menjadi "python manage.py test app" dasar
rprasad

2

Dengan Django 2.2 solusi sederhana dan cukup baik dapat membuat testmap di dalam aplikasi, dan Anda bisa meletakkan test_...pyberkas terkait ke dalamnya , tambahkan saja __init__.pyke testmap.


1

Jika Anda memiliki penyiapan yang lebih rumit, atau tidak ingin menggunakan from ... import *pernyataan -type, Anda dapat menentukan fungsi yang dipanggil suitedi tests.py (atau tests / __ init__.py), yang mengembalikan turunan dari unittest.TestSuite.


0

Saya pikir ./manage.py testhanya menjalankan semua trik tes (dalam django> = 1.7).

Jika tes pengorganisasian Anda tentang pengelompokan dan cherrypicking dan Anda adalah penggemar nosepenggunaan hidung django :

python manage.py test another.test:TestCase.test_method

Jika Anda tahu nose, maka Anda tahu bagaimana "wildcard" jauh lebih baik di semua file Anda.

PS

Ini hanya praktik yang lebih baik. Semoga membantu. Jawabannya dipinjam dari sini: Menjalankan kasus percobaan khusus di Django ketika aplikasi Anda mempunyai direktori percobaan


0

Saya memiliki dua file. Yang satu tests.pydan yang lainnya test_api.py. Saya dapat menjalankannya secara individual seperti di bawah ini.

   manage.py test companies.tests
   manage.py test companies.test_api

Lihat respons @ osa tentang konvensi penamaan file.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.