基于设置的Django Pytest测试URL

时间:2017-07-18 17:17:13

标签: python django pytest urlconf

我在django中有一个端点/docs,我只想在设置中DEBUG = True时显示 - 否则,它应该抛出404.我的设置看起来像这样

urls.py

urlpatterns = ...

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

在进行测试时,django不会自动重新加载urls.py,这意味着简单地覆盖DEBUGTrueFalse不起作用。

我的测试看起来像这样

@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::APIDocsTestWithDebugpytest path/to/test.py::APIDocsTestWithoutDebug单独运行测试时,两个测试都通过了。但是,如果我作为一个整体运行测试文件(pytest path/to/test.py),APIDocsTestWithDebug总是会失败。 他们单独工作而不是一起工作的事实告诉我 url覆盖正在工作,但是当测试同时进行时,有一些错误会让事情变得混乱。我想知道是否有人遇到过类似的问题,或者有一个完全不同的解决方案,或者可以给我一些关于我做错的提示。

2 个答案:

答案 0 :(得分:5)

我在同样的问题上挣扎。问题是Django在初始化时加载了urlpatterns一次 - 并且用装饰器覆盖设置并不会改变最初加载的内容。

这对我有用 - 尝试重新加载urls模块(基于this)并在失败的测试用例之前使用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:您可能还想稍后恢复url模式 - 只需在其他reload_urlconf内运行settings

答案 1 :(得分:0)

您可以使用@pytest.mark.urlshttps://pytest-django.readthedocs.io/en/latest/helpers.html#pytest.mark.urls

@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