У меня есть несколько довольно простых эмпирических правил, за которыми я следую при разработке баз данных, которые я думаю, может использоваться, чтобы помочь принять решения как это....
обычный результат этих правил состоит в том, что начальный дизайн будет способствовать таблицам по столбцам с вниманием на устранение дублирования. В то время как проект прогрессирует, и точки денормализации определяются, полная структура разовьется к балансу, который идет на компромисс с ограниченным дублированием и быстрым увеличением столбца в обмен на другие ценные преимущества.
Спасибо Алексу и Полу. Вот что я придумал:
# 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)
Вот ключевые элементы решения:
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)])
Чтобы добавить рекурсию, используйте os .walk ()
для просмотра дерева модулей и поиска пакетов Python.
Я решил это для себя некоторое время назад:
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
Это позволило мне поместить тесты для каждого модуля в свой собственный файл test.py, чтобы они не перепутались с остальными моего кода приложения. Было бы легко изменить это так, чтобы просто искать тесты документации в каждом из ваших модулей и запускать их, если он их нашел.