10

如果我运行以下命令:

>python manage.py test

Django 在我的应用程序中查看 tests.py,并在该文件中运行任何 doctests 或单元测试。它还查看 __ test __ 字典以运行额外的测试。所以我可以像这样链接来自其他模块的文档测试:

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

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

如果我想包含更多的文档测试,有没有比在这本词典中枚举它们更简单的方法?理想情况下,我只想让 Django 在 myapp 应用程序的所有模块中找到所有文档测试。

是否有某种反射技巧可以让我到达我想去的地方?

4

5 回答 5

2

不久前我为自己解决了这个问题:

应用程序 = settings.INSTALLED_APPS

对于应用程序中的应用程序:
    尝试:
        a = 应用程序 + '.test'
        __import__(a)
        m = sys.modules[a]
    除了 ImportError: #no test jobs for this module, 继续下一个
        继续
    #使用导入的模块 m 运行测试

这使我可以将每个模块的测试放在他们自己的 test.py 文件中,因此它们不会与我的应用程序代码的其余部分混淆。将其修改为仅在每个模块中查找文档测试并在找到它们时运行它们会很容易。

于 2009-10-29T03:04:19.990 回答
2

使用django-nose,因为鼻子会自动递归查找所有测试。

于 2012-04-09T19:54:15.433 回答
1

以下是解决方案的关键要素:

测试.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)])

添加递归用于os.walk()遍历模块树并查找 python 包。

于 2009-10-29T02:36:03.123 回答
1

我没有跟上 Djano 的测试速度,但据我了解,它使用自动单元测试发现,就像python -m unittest discover和鼻子一样。

如果是这样,只需将以下文件放在发现将找到它的位置(通常只是命名test_doctest.py或类似的问题)。

换成your_package要测试的包。所有模块(包括子包)都将进行文档测试。

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
于 2014-10-10T18:37:09.817 回答
1

感谢亚历克斯和保罗。这就是我想出的:

# 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)
于 2009-10-31T05:01:52.933 回答