Django SECURE_SSL_REDIRECT 破坏了使用内置客户端的单元测试

Posted

技术标签:

【中文标题】Django SECURE_SSL_REDIRECT 破坏了使用内置客户端的单元测试【英文标题】:Django SECURE_SSL_REDIRECT breaks unit tests that use the in-built client 【发布时间】:2018-09-12 14:13:13 【问题描述】:

我正在处理一个已经有数百个单元测试的项目,其中许多使用内置的 django 客户端或 django rest 框架 APIClient 来发出请求和测试响应。

最近实现了使 SSL 在本地工作的必要条件,并将 SECURE_SSL_REDIRECT 设置为 True(试图使我们的 dockerised devtest 环境尽可能接近production 可能),我发现这么多单元测试失败了,因为(API)客户端请求,默认情况下,总是使用http,而不是https。

许多(大多数)请求如下所示:

response = self.client.get(some_url)

我知道我可以使用:

response = self.client.get(some_url, secure=True)

但这确实意味着要更改很多单元测试。使用 follow=True 也是如此,但还有一个额外的缺点,那就是这可能会产生一些其他不受欢迎的行为。

我看不到在 Django 客户端中将安全请求的使用设置为默认行为的方法。我可以制作自己的 SecureClient(和 SecureAPIClient),但我必须确保创建一个新的基础 TestCase(可能是多个)来继承,并为所有测试在任何地方更改它 - 仍然有很多工作。

当然可以对客户端进行猴子补丁,但我不愿意这样做,因为它可能会产生以后难以调试的不良影响。

TLDR;是否有一种简单(理想支持)的方式,通过 django 测试的客户端发出所有单元测试请求,默认使用 SSL?

【问题讨论】:

【参考方案1】:

选项 1. 在需要时禁用 SECURE_SSL_REDIRECT

from django.test import override_settings

class FooTest(TestCase):

    def setUp(self):
        settings_manager = override_settings(SECURE_SSL_REDIRECT=False)
        settings_manager.enable()
        self.addCleanup(settings_manager.disable)

选项 2:包装 APIClientgetpost 方法:

class ApiTestCase(TestCase):
    def setUp(self):
        self.client = APIClient()

    def get(self, *args, **kwargs):
        return self.client.get(secure=True, *args, **kwargs)

    def post(self, *args, **kwargs):
        return self.client.post(secure=True, *args, **kwargs)

选项 3:只需为测试环境维护一个单独的设置文件,而不设置 SECURE_SSL_REDIRECT

我已经尝试了所有三个选项,并建议使用 (3)。原因如下:

    django.test.client 只是对真实客户的模仿。它可以对您的视图进行单元测试。它不会产生真正的 WSGI 请求,因此测试环境无论如何都不会匹配生产环境。

    SECURE_SSL_REDIRECTSecurityMiddleware 设置。 Don't unit test third-party code。

    确保您的代码始终使用 SSL 是一个很好的目标。然而,这是一个集成测试问题。适合这项工作的工具是 Selenium + LiveServerTestCase。

【讨论】:

【参考方案2】:

如果您使用pytestpytest-django,您还可以制作一个修改测试客户端的fixture:

import functools
import pytest

@pytest.fixture
def client(client):
    client.get = functools.partial(client.get, secure=True)
    client.post = functools.partial(client.post, secure=True)
    return client

【讨论】:

【参考方案3】:

这是一个有趣的问题,我在不更改现有单元测试的情况下解决它的方法是在运行测试时修改 manage.py 以设置 SECURE_SSL_REDIRECT = False

你可以简单地导入

from django.conf import settings

在manage.py中 并添加

    # Disable HTTPS redirects while testing with Django's HTTP test client.
    if len(sys.argv) > 1 and sys.argv[1] == "test":
        settings.SECURE_SSL_REDIRECT = False

之前

execute_from_command_line(sys.argv)

【讨论】:

以上是关于Django SECURE_SSL_REDIRECT 破坏了使用内置客户端的单元测试的主要内容,如果未能解决你的问题,请参考以下文章

Django之路

Django系列

django 错误

mac电脑安装django ,运行django报错解决

Django 大神带你飞系列~走进Django

django的文档