لدي هيكل المشروع التالي:
myapp/settings/__init__.py
myapp/settings/base.py
myapp/settings/test.py
داخل base.py
لدي إعداد يسمى REST_FRAMEWORK من مشروع إطار عمل Django REST. test.py
بعمل from myapp.settings.base import *
في الأعلى ثم يضيف بعض إعدادات قاعدة البيانات الخاصة به. الآن ، لسبب ما ، يتجاهل pytest تمامًا إعداد REST_FRAMEWORK على الرغم من تحميل الملف test.py
ويمكنني طباعة محتويات REST_FRAMEWORK بداخله. يعمل Django كما هو متوقع.
إذا قمت بنسخ إعداد REST_FRAMEWORK يدويًا إلى ملف test.py
بدلاً من الاعتماد على التمديد ، فستنجح اختباراتي. أيه أفكار؟ تبدو هذه حالة بسيطة لدرجة أنني يجب أن أفتقد شيئًا ما ولكن لا يمكنني تعقبه.
pytest 2.7.2 و pytest-django 2.8.0
هل أنت متأكد من تعيين DJANGO_SETTINGS_MODULE
بشكل صحيح؟
ها هو pytest.ini الخاص بي:
[pytest]
DJANGO_SETTINGS_MODULE=myapp.settings.test
norecursedirs=venv .git build
وقمت أيضًا بتعيينه في سطر الأوامر باستخدام --ds=myapp.settings.test
دون جدوى
طيب غريب.
هل يمكنك إضافة import pdb; pdb.set_trace()
قبل استيراد base
ثم معرفة المكان الذي يتم استدعاؤه منه ( bt
) ، ثم s
tep لرؤية ذلك ما الذي يجري.
من هنا يأتي:
$ py.test -vxsk test_public_api
> ~/projects/myapp/settings/test.py(2)<module>()
1 import ipdb;ipdb.set_trace()
----> 2 from myapp.settings.base import * # pylint: disable=W0614,W0401
3
ipdb> bt
~/.virtualenvs/myapp/bin/py.test(11)<module>()
7 from pytest import main
8
9 if __name__ == '__main__':
10 sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
---> 11 sys.exit(main())
~/.virtualenvs/myapp/local/lib/python2.7/site-packages/_pytest/config.py(32)main()
30 """
31 try:
---> 32 config = _prepareconfig(args, plugins)
33 except ConftestImportFailure:
34 e = sys.exc_info()[1]
~/.virtualenvs/myapp/local/lib/python2.7/site-packages/_pytest/config.py(85)_prepareconfig()
83 pluginmanager.register(plugin)
84 return pluginmanager.hook.pytest_cmdline_parse(
---> 85 pluginmanager=pluginmanager, args=args)
86 except Exception:
87 pluginmanager.ensure_shutdown()
~/.virtualenvs/myapp/local/lib/python2.7/site-packages/_pytest/core.py(521)__call__()
519
520 def __call__(self, **kwargs):
--> 521 return self._docall(self.methods, kwargs)
522
523 def callextra(self, methods, **kwargs):
~/.virtualenvs/myapp/local/lib/python2.7/site-packages/_pytest/core.py(528)_docall()
526 def _docall(self, methods, kwargs):
527 return MultiCall(methods, kwargs,
--> 528 firstresult=self.firstresult).execute()
529
530
~/.virtualenvs/myapp/local/lib/python2.7/site-packages/_pytest/core.py(393)execute()
391 args = [all_kwargs[argname] for argname in varnames(method)]
392 if hasattr(method, "hookwrapper"):
--> 393 return wrapped_call(method(*args), self.execute)
394 res = method(*args)
395 if res is not None:
~/.virtualenvs/myapp/local/lib/python2.7/site-packages/_pytest/core.py(107)wrapped_call()
105 except StopIteration:
106 raise_wrapfail(wrap_controller, "did not yield")
--> 107 call_outcome = CallOutcome(func)
108 try:
109 wrap_controller.send(call_outcome)
~/.virtualenvs/myapp/local/lib/python2.7/site-packages/_pytest/core.py(123)__init__()
121 def __init__(self, func):
122 try:
--> 123 self.result = func()
124 except BaseException:
125 self.excinfo = sys.exc_info()
~/.virtualenvs/myapp/local/lib/python2.7/site-packages/_pytest/core.py(394)execute()
392 if hasattr(method, "hookwrapper"):
393 return wrapped_call(method(*args), self.execute)
--> 394 res = method(*args)
395 if res is not None:
396 self.results.append(res)
~/.virtualenvs/myapp/local/lib/python2.7/site-packages/_pytest/config.py(636)pytest_cmdline_parse()
634 def pytest_cmdline_parse(self, pluginmanager, args):
635 assert self == pluginmanager.config, (self, pluginmanager.config)
--> 636 self.parse(args)
637 return self
638
~/.virtualenvs/myapp/local/lib/python2.7/site-packages/_pytest/config.py(746)parse()
744 "can only parse cmdline args at most once per Config object")
745 self._origargs = args
--> 746 self._preparse(args)
747 # XXX deprecated hook:
748 self.hook.pytest_cmdline_preparse(config=self, args=args)
~/.virtualenvs/myapp/local/lib/python2.7/site-packages/_pytest/config.py(718)_preparse()
716 try:
717 self.hook.pytest_load_initial_conftests(early_config=self,
--> 718 args=args, parser=self._parser)
719 except ConftestImportFailure:
720 e = sys.exc_info()[1]
~/.virtualenvs/myapp/local/lib/python2.7/site-packages/_pytest/core.py(521)__call__()
519
520 def __call__(self, **kwargs):
--> 521 return self._docall(self.methods, kwargs)
522
523 def callextra(self, methods, **kwargs):
~/.virtualenvs/myapp/local/lib/python2.7/site-packages/_pytest/core.py(528)_docall()
526 def _docall(self, methods, kwargs):
527 return MultiCall(methods, kwargs,
--> 528 firstresult=self.firstresult).execute()
529
530
~/.virtualenvs/myapp/local/lib/python2.7/site-packages/_pytest/core.py(393)execute()
391 args = [all_kwargs[argname] for argname in varnames(method)]
392 if hasattr(method, "hookwrapper"):
--> 393 return wrapped_call(method(*args), self.execute)
394 res = method(*args)
395 if res is not None:
~/.virtualenvs/myapp/local/lib/python2.7/site-packages/_pytest/core.py(107)wrapped_call()
105 except StopIteration:
106 raise_wrapfail(wrap_controller, "did not yield")
--> 107 call_outcome = CallOutcome(func)
108 try:
109 wrap_controller.send(call_outcome)
~/.virtualenvs/myapp/local/lib/python2.7/site-packages/_pytest/core.py(123)__init__()
121 def __init__(self, func):
122 try:
--> 123 self.result = func()
124 except BaseException:
125 self.excinfo = sys.exc_info()
~/.virtualenvs/myapp/local/lib/python2.7/site-packages/_pytest/core.py(394)execute()
392 if hasattr(method, "hookwrapper"):
393 return wrapped_call(method(*args), self.execute)
--> 394 res = method(*args)
395 if res is not None:
396 self.results.append(res)
~/.virtualenvs/myapp/local/lib/python2.7/site-packages/pytest_django/plugin.py(87)pytest_load_initial_conftests()
85 if pytest.__version__[:3] >= "2.4":
86 def pytest_load_initial_conftests(early_config, parser, args):
---> 87 _load_settings(early_config, parser.parse_known_args(args))
88
89
~/.virtualenvs/myapp/local/lib/python2.7/site-packages/pytest_django/plugin.py(79)_load_settings()
77 from django.conf import settings
78 try:
---> 79 settings.DATABASES
80 except ImportError:
81 e = sys.exc_info()[1]
~/.virtualenvs/myapp/local/lib/python2.7/site-packages/django/conf/__init__.py(48)__getattr__()
46 def __getattr__(self, name):
47 if self._wrapped is empty:
---> 48 self._setup(name)
49 return getattr(self._wrapped, name)
50
~/.virtualenvs/myapp/local/lib/python2.7/site-packages/django/conf/__init__.py(44)_setup()
42 % (desc, ENVIRONMENT_VARIABLE))
43
---> 44 self._wrapped = Settings(settings_module)
45
46 def __getattr__(self, name):
~/.virtualenvs/myapp/local/lib/python2.7/site-packages/django/conf/__init__.py(92)__init__()
90 self.SETTINGS_MODULE = settings_module
91
---> 92 mod = importlib.import_module(self.SETTINGS_MODULE)
93
94 tuple_settings = (
/usr/lib/python2.7/importlib/__init__.py(37)import_module()
34 break
35 level += 1
36 name = _resolve_name(name[level:], package, level)
---> 37 __import__(name)
38 return sys.modules[name]
> ~/projects/myapp/settings/test.py(2)<module>()
1 import ipdb;ipdb.set_trace()
----> 2 from myapp.settings.base import * # pylint: disable=W0614,W0401
3
4 DEBUG = False
5 TEMPLATE_DEBUG = DEBUG
وبمجرد أن أتخطى عملية الاستيراد REST_FRAMEWORK
متاحًا ولديه الإعدادات الصحيحة من base.py
. بمجرد أن أخطو في هذا الملف وينتقل إلى إعدادات django الداخلية ، يمكنني الحصول على الإعدادات. REST_FRAMEWORK وهو صحيح أيضًا. ولكن إذا ضغطت على c
لمواصلة الاختبار ، فإنه يفشل مع وجود أخطاء تشير إلى أنه لا يعمل بالفعل مع القيم المستوردة من base.py
. القيم من DATABASES
stick ، فقط ليست من REST_FRAMEWORK
.
هل يمكنك تقليل هذا إلى الحد الأدنى من المشروع باستخدام ملفات إعدادات متعددة حيث يمكن تكرار المشكلة؟
اكتشفت أن قيمة DJANGO_SETTINGS_MODULE
في pytest.ini
لا تتجاوز متغير البيئة DJANGO_SETTINGS_MODULE
. لدي أيضًا ملف إعدادات للاختبار مشتق من ملف إعدادات آخر - يستخدم pytest ملف الإعدادات الأساسي نظرًا لأن هذه هي القيمة في متغير البيئة.
@ smcoll صحيح. يبدو أن قيمة ENV تتجاوز قيمة INI / config:
بالنسبة لنا ، نحن قادرون على عمل الأشياء عبر DJANGO_SETTINGS_MODULE=config.settings.test pytest
لأننا نقوم بتشغيل الأشياء محليًا باستخدام Docker / Compose والذي يتم تعيينه افتراضيًا على config.settings.local في ENV.
أشعر أن pytest-django يفعل الشيء الصحيح ولكني أتساءل أيضًا عما إذا كان يجب أن يفوق التكوين البيئة المحيطة؟
لقد حصلت للتو على القليل من هذه القضية. أعتقد أن التكوين يجب أن يتفوق على البيئة ، شخصيًا ...
ترتيب الاكتشاف موثق هنا .
يعد envvar تقليديًا أقوى من ملف التكوين ، لذلك هذا هو السلوك المتوقع ، وبسبب التوافق مع الإصدارات السابقة من غير المرجح أن يتغير على أي حال.
طريقة واحدة لخداع هذا هو الاستخدام
[pytest]
addopts = --ds=my_settings
بدلاً من إعداد DJANGO_SETTINGS_MODULE
. يكون لعلم سطر الأوامر الأسبقية على أي شيء آخر.
التعليق الأكثر فائدة
اكتشفت أن قيمة
DJANGO_SETTINGS_MODULE
فيpytest.ini
لا تتجاوز متغير البيئةDJANGO_SETTINGS_MODULE
. لدي أيضًا ملف إعدادات للاختبار مشتق من ملف إعدادات آخر - يستخدم pytest ملف الإعدادات الأساسي نظرًا لأن هذه هي القيمة في متغير البيئة.