Configura Django per trovare tutti i doctest in tutti i moduli?
-
06-07-2019 - |
Domanda
Se eseguo il seguente comando:
>python manage.py test
Django esamina tests.py nella mia applicazione ed esegue tutti i doctest o unit test in quel file. Guarda anche il dizionario __ test __ per l'esecuzione di ulteriori test. Quindi posso collegare doctest da altri moduli in questo modo:
#tests.py
from myapp.module1 import _function1, _function2
__test__ = {
"_function1": _function1,
"_function2": _function2
}
Se voglio includere più doctest, c'è un modo più semplice di elencarli tutti in questo dizionario? Idealmente, voglio solo che Django trovi tutti i doctest in tutti i moduli nell'applicazione myapp.
Esiste una sorta di hack di riflessione che mi porterebbe dove voglio essere?
Soluzione 4
Grazie ad Alex e Paul. Questo è quello che mi è venuto in mente:
# tests.py
import sys, settings, re, os, doctest, unittest, imp
# import your base Django project
import myapp
# Django already runs these, don't include them again
ALREADY_RUN = ['tests.py', 'models.py']
def find_untested_modules(package):
""" Gets all modules not already included in Django's test suite """
files = [re.sub('\.py, '', f)
for f in os.listdir(os.path.dirname(package.__file__))
if f.endswith(".py")
and os.path.basename(f) not in ALREADY_RUN]
return [imp.load_module(file, *imp.find_module(file, package.__path__))
for file in files]
def modules_callables(module):
return [m for m in dir(module) if callable(getattr(module, m))]
def has_doctest(docstring):
return ">>>" in docstring
__test__ = {}
for module in find_untested_modules(myapp.module1):
for method in modules_callables(module):
docstring = str(getattr(module, method).__doc__)
if has_doctest(docstring):
print "Found doctest(s) " + module.__name__ + "." + method
# import the method itself, so doctest can find it
_temp = __import__(module.__name__, globals(), locals(), [method])
locals()[method] = getattr(_temp, method)
# Django looks in __test__ for doctests to run
__test__[method] = getattr(module, method)
Altri suggerimenti
L'ho risolto da solo un po 'di tempo fa:
apps = settings.INSTALLED_APPS for app in apps: try: a = app + '.test' __import__(a) m = sys.modules[a] except ImportError: #no test jobs for this module, continue to next one continue #run your test using the imported module m
Questo mi ha permesso di mettere i test per modulo nel loro file test.py, quindi non si sono confusi con il resto del mio codice dell'applicazione. Sarebbe facile modificarlo per cercare i test dei documenti in ciascuno dei tuoi moduli ed eseguirli se li trovassero.
Usa django-nose poiché nose trova automaticamente tutti i test in modo ricorsivo.
Ecco gli elementi chiave della soluzione:
tests.py:
def find_modules(package):
"""Return list of imported modules from given package"""
files = [re.sub('\.py
Per aggiungere la ricorsione usa os.walk ()
per attraversare l'albero dei moduli e trovare i pacchetti python.
, '', f) for f in os.listdir(os.path.dirname(package.__file__))
if f.endswith(".py") and os.path.basename(f) not in ('__init__.py', 'test.py')]
return [imp.load_module(file, *imp.find_module(file, package.__path__)) for file in files]
def suite(package=None):
"""Assemble test suite for Django default test loader"""
if not package: package = myapp.tests # Default argument required for Django test runner
return unittest.TestSuite([doctest.DocTestSuite(m) for m in find_modules(package)])
Per aggiungere la ricorsione usa os.walk ()
per attraversare l'albero dei moduli e trovare i pacchetti python.
Non sono al passo con i test di Djano, ma a quanto ho capito usa automaticamente unittest discovery, proprio come python -m unittest discover
e Nose.
In tal caso, basta posizionare il seguente file in un punto in cui la scoperta lo troverà (in genere si tratta solo di nominarlo test_doctest.py
o simile).
Cambia your_package
nel pacchetto da testare. Tutti i moduli (compresi i pacchetti secondari) saranno sottoposti a test documentale.
import doctest
import pkgutil
import your_package as root_package
def load_tests(loader, tests, ignore):
modules = pkgutil.walk_packages(root_package.__path__, root_package.__name__ + '.')
for _, module_name, _ in modules:
try:
suite = doctest.DocTestSuite(module_name)
except ValueError:
# Presumably a "no docstrings" error. That's OK.
pass
else:
tests.addTests(suite)
return tests