Configure Django to find all doctests in all modules?

≡放荡痞女 提交于 2019-12-12 07:48:35

问题


If I run the following command:

>python manage.py test

Django looks at tests.py in my application, and runs any doctests or unit tests in that file. It also looks at the __ test __ dictionary for extra tests to run. So I can link doctests from other modules like so:

#tests.py
from myapp.module1 import _function1, _function2

__test__ = {
    "_function1": _function1,
    "_function2": _function2
}

If I want to include more doctests, is there an easier way than enumerating them all in this dictionary? Ideally, I just want to have Django find all doctests in all modules in the myapp application.

Is there some kind of reflection hack that would get me where I want to be?


回答1:


I solved this for myself a while ago:

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

This allowed me to put per-module tests in their own test.py file, so they didn't get mixed up with the rest of my application code. It would be easy to modify this to just look for doc tests in each of your modules and run them if it found them.




回答2:


Use django-nose since nose automatically find all tests recursivelly.




回答3:


Here're key elements of solution:

tests.py:

def find_modules(package):
    """Return list of imported modules from given package"""
    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 ('__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)])

To add recursion use os.walk() to traverse module tree and find python packages.




回答4:


Thanks to Alex and Paul. This is what I came up with:

# 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)



回答5:


I'm not up to speed on Djano's testing, but as I understand it uses automatic unittest discovery, just like python -m unittest discover and Nose.

If so, just put the following file somewhere the discovery will find it (usually just a matter of naming it test_doctest.py or similar).

Change your_package to the package to test. All modules (including subpackages) will be doctested.

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


来源:https://stackoverflow.com/questions/1615406/configure-django-to-find-all-doctests-in-all-modules

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!