Тестовый Django Pytest URL на основе настроек

У меня есть конечная точка /docs в Django, что я хочу видеть только когда DEBUG = True в настройках - иначе должен выкинуть 404. Моя настройка выглядит так

urls.py

urlpatterns = ...

if settings.DEBUG:
    urlpatterns += [
            url(r'^docs/$', SwaggerSchemaView.as_view(), name='api_docs'),
    ]

Однако при тестировании django не перезагружается автоматически urls.py, что означает просто переопределение DEBUG в True или же False не работает

Мои тесты выглядят примерно так

@override_settings(DEBUG=True)
@override_settings(ROOT_URLCONF='config.urls')
class APIDocsTestWithDebug(APITestCase):
    # check for 200s
    ...

@override_settings(DEBUG=False)
@override_settings(ROOT_URLCONF='config.urls')
class APIDocsTestWithoutDebug(APITestCase):
    # check for 404s
    ...

Теперь вот странная часть: когда я запускаю тесты по отдельности, используя pytest path/to/test.py::APIDocsTestWithDebug а также pytest path/to/test.py::APIDocsTestWithoutDebugОба теста проходят. Тем не менее, если я запускаю тестовый файл в целом (pytest path/to/test.py), APIDocsTestWithDebug всегда терпит неудачу. Тот факт, что они работают по отдельности, но не вместе, говорит мне, что переопределение URL работает, но когда тесты выполняются в тандеме, возникает некоторая ошибка, которая портит ситуацию. Мне было интересно, сталкивался ли кто-нибудь с подобной проблемой и имеет ли совершенно другое решение, или может дать мне несколько советов относительно того, что я делаю неправильно.

3 ответа

Я боролся с той же проблемой. Дело в том, что Django загружает ваши urlpatterns один раз при инициализации - и переопределение настроек декоратором не меняет то, что было изначально загружено.

Вот что сработало для меня - попробуйте перезагрузить свой urls модуль (основанный на этом) и очистка кэшей URL с clear_url_caches() до неудачных тестов:

import sys

from importlib import reload, import_module

from django.conf import settings
from django.core.urlresolvers import clear_url_caches

def reload_urlconf(urlconf=None):
    clear_url_caches()
    if urlconf is None:
        urlconf = settings.ROOT_URLCONF
    if urlconf in sys.modules:
        reload(sys.modules[urlconf])
    else:
        import_module(urlconf)

PS: Вы также можете позже восстановить urlpatterns - просто запустите reload_urlconf в других settings,

Вы можете использовать @pytest.mark.urls: https://pytest-django.readthedocs.io/en/latest/helpers.html

@pytest.mark.urls('myapp.test_urls')
def test_something(client):
    assert 'Success!' in client.get('/some_url_defined_in_test_urls/').content

Вы даже можете определить URL-адреса в одном файле:

def some_view(request):
    return HttpResponse(b"Success!")


urlpatterns = [
    path("some-url/", some_view)
]


@pytest.mark.urls(__name__)
def test_something(client):
    assert b'Success!' in client.get('/some-url/').content

Основываясь на ответе Сергея Никифорова, я реализовал пакет Pypi с контекстным менеджером для загрузки/перезагрузки URL-адресов.

Страница Github: https://github.com/karpyncho/reload-urls

Установить:

      pip install karpyncho_reload_urls

тогда вы просто наследуете свой класс костюма TestCase от TestCaseReloadableURL

и вы можете просто использовать:

      from karpyncho.reload_urls import TestCaseReloadableURL
 
class TestMyClass(TestCaseReloadableURL)
def my_test(self):
    with self.reload_urls(DEBUG=True):
        # put your checks here

это перезагрузит ваши настройки только в контекстном блоке

вы можете предлагать улучшения..

Другие вопросы по тегам