基于设置的 Django Pytest 测试 URL

Posted

技术标签:

【中文标题】基于设置的 Django Pytest 测试 URL【英文标题】:Django Pytest Test URL Based on Settings 【发布时间】:2017-12-23 16:54:55 【问题描述】:

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

urls.py

urlpatterns = ...

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

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

我的测试看起来像这样

@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 覆盖正在工作,但是当测试串联时,会出现一些将事情搞砸的错误。我想知道是否有人遇到过类似的问题,或者有完全不同的解决方案,或者可以给我一些关于我做错了什么的提示。

【问题讨论】:

我不会这么说 - 这个问题是覆盖设置的核心功能的问题 - 我的问题是,虽然我可以覆盖 DEBUG,但我的 url 是基于定义的DEBUG 是否为 True。我需要找到一种方法来重新生成 URL 或类似的东西 如何在urls.py 中导入设置? from django.conf import settings 我会取下旗帜。你说得对,这是一个不同的问题。 您可以尝试使用include 【参考方案1】:

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

这对我有用 - 尝试重新加载您的 urls 模块(基于 this)并在失败的测试用例之前使用 clear_url_caches() 清除 url 缓存:

import sys

from importlib import reload, import_module

from django.conf import settings
from django.core.urlresolvers import clear_url_caches  # Or -> from django.urls 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 - 只需在其他 settings 中运行 reload_urlconf

【讨论】:

谢谢你,很好的回答。 这是正确的。 url 注册表仅在测试套件和应用程序运行时加载一次。因此,即使您在运行时更改了 env var,加载时的初始 urlpatterns(基于 env var)也不会改变。您可以更改 env var 然后重新加载,但请确保在重置状态是意图的情况下恢复它。【参考方案2】:

你可以使用@pytest.mark.urls:https://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

【讨论】:

以上是关于基于设置的 Django Pytest 测试 URL的主要内容,如果未能解决你的问题,请参考以下文章

PyTest-Django 在缺少 django_migration 表时失败

Docker Pytest容器在完成测试过程后仍处于启动状态

pytest

pytest 框架与 unittest 框架的对比

在 pytest 中使用不同的数据库

基于Python豆瓣自动化测试