我正在开发一个已经有数百个单元测试的项目,其中许多使用内置的django客户端或django rest框架APIClient来发出请求和测试响应。
最近已实施必要条件以使SSL在本地工作,并将SECURE_SSL_REDIRECT
设置为True(尝试使我们的dockerised dev
和test
环境接近production
因为可能),我找到了一个裁剪器,发现很多单元测试都失败了,因为(API)客户端默认情况下请求使用http,而不是https。
许多(大多数)请求看起来像这样:
response = self.client.get(some_url)
我知道我可以使用:
response = self.client.get(some_url, secure=True)
但这确实意味着改变很多的单元测试。使用follow=True
也是如此,但有一个额外的缺点,即这会产生一些其他不良行为。
我无法看到将安全请求的使用设置为Django Client中的默认行为的方法。我可以创建自己的SecureClient(和SecureAPIClient),但我必须确保我创建一个新的基础TestCase(可能是多个)来继承,并在所有测试的每个地方进行更改 - 仍然需要做很多工作。 / p>
当然可以对客户端进行修补,但我不愿意这样做,因为它可能会产生以后难以调试的不良影响。
TLDR;是否有一种简单(理想支持)的方式,通过django测试的客户端进行所有单元测试请求,默认情况下使用SSL?
答案 0 :(得分:3)
选项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:包裹get
的{{1}}和post
方法:
APIClient
选项3:只为未设置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
只是对真实客户的模仿。它可以对您的观点进行单元测试。它不会产生真正的WSGI请求,因此测试环境无论如何都不会匹配生产环境。
django.test.client
是SECURE_SSL_REDIRECT
设置。 Don't unit test third-party code。
确保您的代码始终使用SSL是一个很好的目标。但是,这是集成测试问题。这项工作的正确工具是Selenium + LiveServerTestCase。
答案 1 :(得分:1)
如果您使用的是pytest
和pytest-django
,则还可以制作修改测试客户端的设备:
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
答案 2 :(得分:0)
这是一个有趣的问题,我在不更改现有单元测试的情况下解决它的方法是修改 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)