Come distribuire gli unit test django su più file?


126
  • Ho un'applicazione python-django
  • Sto usando il framework di unit test
  • I test sono organizzati nel file "tests.py" nella directory del modulo
  • Sto eseguendo i test tramite ./manage.py test app

Adesso..

  • Il tests.pyfile sta diventando piuttosto grande / complesso / disordinato
  • Vorrei suddividere tests.pyin raccolte più piccole di test ...

Come?

Risposte:


47

Il comportamento è cambiato in Django 1.6, quindi non è più necessario creare un pacchetto. Dai un nome ai tuoi file test*.py.

Dalla documentazione di Django 1.7

Quando si eseguono i test, il comportamento predefinito dell'utilità di test è trovare tutti i casi di test (ovvero, sottoclassi di unittest.TestCase) in qualsiasi file il cui nome inizia con test, costruire automaticamente una suite di test da quei casi di test, e gestisci quella suite.

Dalla documentazione di Django 1.6 ,

Il rilevamento del test si basa sul rilevamento del test integrato del modulo unittest. Per impostazione predefinita, questo rileverà i test in qualsiasi file denominato "test * .py" nella directory di lavoro corrente.

Comportamento precedente, dalla documentazione di Django 1.5 :

Quando si eseguono i test, il comportamento predefinito dell'utilità di test è trovare tutti i casi di test (cioè le sottoclassi di unittest.TestCase) in models.py e tests.py, creare automaticamente una suite di test da questi casi di test, e gestisci quella suite.

C'è un secondo modo per definire la suite di test per un modulo: se definisci una funzione chiamata suite () in models.py o tests.py, il test runner Django utilizzerà quella funzione per costruire la suite di test per quel modulo. Questo segue l'organizzazione suggerita per i test unitari. Vedere la documentazione di Python per maggiori dettagli su come costruire una suite di test complessa.


4
In django 2.6 non scopre davvero nulla…
LtWorf

2
Attualmente usando Django 1.10, volevo mettere tutti i miei test*.pyfile in una cartella chiamata testsper mantenere la cartella pulita - questo è possibile, ma devi eseguire ./manage.py test app.testse tutte le importazioni relative devono salire di un livello ( from .modelsdiventa from ..models).
Scott Stevens

123

Nota che questo approccio non è più valido da Django 1.6, vedi questo post .

Puoi creare una testscartella con ___init___.pydentro (in modo che diventi un pacchetto). Quindi aggiungi lì i tuoi file .py di split test e li importi tutti in ___init___.py.

Vale a dire: sostituire il test.pyfile con un modulo che ha l'aspetto e si comporta come il file:

Crea una testsdirectory sotto l'app in questione

App
app \ models.py
app \ views.py
test app \
app \ test \ __ init__.py
app \ test \ bananas.py
app \ test \ apples.py

Importa i sottomoduli in app\tests\__init__.py:

from bananas import *
from apples import *

Ora puoi usare ./manage.py come se fossero tutti in un unico file:

./manage.py test app.some_test_in_bananas

1
Doh. Intendevi creare un modulo "test" sotto l'applicazione che sto testando; non una nuova applicazione chiamata test. Adesso capisco. Eccezionale. Grazie!
John Mee

@ John: non riesco più a riconoscere la mia risposta! :-) Ma hai perfettamente ragione sul fatto che fosse troppo vago, anche se corretto - i tuoi esempi lo rendono chiaro, contrariamente alla mia formulazione originale.
Tomasz Zieliński

2
@ Tomasz .. Le tue parole sono ancora lì - del tutto intatte. Ho solo rimpolpato un po 'da quando mi hai messo sulla strada giusta.
John Mee

@ John: non ero affatto arrabbiato se è questo che intendi :) È stato divertente vedere la mia risposta in una forma leggermente diversa
Tomasz Zieliński

4
@jMyles, se per "normale test runner django" intendi python manage.py test myappallora in effetti questa risposta funziona perfettamente. (l'ho appena provato)
Kirk Woll

27

La risposta come affermato da Tomasz è corretta. Tuttavia, può diventare noioso assicurarsi che le importazioni __init__.pycorrispondano alla struttura del file.

Per rilevare automaticamente tutti i test nella cartella puoi aggiungerlo in __init__.py:

import unittest

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

Ciò ti consentirà di eseguire ./manage.py test appnamema non gestirà l'esecuzione di test specifici. Per farlo puoi usare questo codice (anche in __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__)

Ora puoi eseguire tutti i tuoi test tramite manage.py test appo specifici tramitemanage.py test app.TestApples


Dove metti il ​​secondo pezzo?
rh0dium

Entrambi i pezzi entrano in__init__.py
Bryce Drennan

Si noti che se uno qualsiasi dei nomi dei pacchetti di test coincide con i nomi dei moduli di primo livello che vengono importati durante l'esecuzione del test, lo snippet di pkgutil farà fallire l'importazione perché i test vengono aggiunti come sys.modules[packagename]. Una soluzione rapida è quella delche causa problemi dopo quanto sopra. (Oppure potresti rinominare le tue cartelle;))
Paul Fenney

Questo è fantastico ma mi sono imbattuto in un errore in cui, durante l'esecuzione di un test a livello di app ( python manage.py test appName), il secondo bit di codice generava un errore che indicava che __path__non era disponibile. L'ho evitato avvolgendo il secondo frammento in un if '__path__' in locals():assegno, che ha funzionato. Grazie per la risposta!
alukach

1
+1 questo garantisce anche che il file init aderisca agli standard di codifica comuni, ovvero non abbia * o importazioni inutilizzate
Martin B.

13

Basta creare la struttura della directory in questo modo:

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

E python manage.py test myappfunzionerà come previsto.



2

Non è necessario codificare nulla in init. Basta creare una sottodirectory nella tua app. L'unico requisito è non chiamarlo test * Ad esempio

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

1
Perché non puoi chiamarlo qualcosa che inizia con "test"?
Serp C

Sto usando questa risposta con Django 1.11.4. Motivi per usarlo: (1) Il file "app / testing / __ init__.py" rimane vuoto e (2) Il comando rimane il "python manage.py test app" di base
rprasad

2

Con Django 2.2 una soluzione semplice e abbastanza buona potrebbe essere quella di creare una testcartella all'interno di un'app, in cui puoi inserire i tuoi test_...pyfile correlati , semplicemente aggiungerli __init__.pyalla testcartella.


1

Se hai una configurazione più complicata o non vuoi usare le from ... import *istruzioni -type, puoi definire una funzione chiamata suitenel tuo tests.py (o tests / __ init__.py), che restituisce un'istanza di unittest.TestSuite.


0

Penso ./manage.py testche esegua semplicemente tutti i trucchi dei test (in django> = 1.7).

Se i tuoi test di organizzazione riguardano il raggruppamento e il cherrypicking e sei un fan nosedell'uso di django nose :

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

Se conosci il naso, allora sai come "jolly" molto più bello su tutti i tuoi file.

PS

È solo una pratica migliore. Spero che aiuti. La risposta è stata presa in prestito da qui: Esecuzione di uno specifico test case in Django quando la tua app ha una directory di test


0

Ho due file. Uno è tests.pye l'altro è test_api.py. Posso eseguirli individualmente come di seguito.

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

Fare riferimento alla risposta di @ osa sulla convenzione di denominazione dei file.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.