python - 测试期间在 Django 视图中无法访问请求之前设置的会话变量
问题描述
我需要在 HTTP 请求之间存储一种状态。因为我不使用 JS 前端,所以我决定使用存储在 cookie 中的会话变量。我的会话设置如下所示:
SESSION_ENGINE = "django.contrib.sessions.backends.signed_cookies"
SESSION_COOKIE_HTTPONLY = False
我需要一个函数来轻松操作一个会话变量。因为这个功能非常简单,所以我决定特别使用基于函数的视图:
def set_category_filter(request, pk):
if pk == 0:
if 'filter_category_id' in request.session: # this is False during unit testing, but it's ok in a normal app run
del request.session['filter_category_id']
else:
get_object_or_404(Category, pk=pk, user=request.user)
request.session['filter_category_id'] = pk
return redirect('index')
问题是当我想取消设置此会话变量时,我无法测试用例。假设会话变量filter_category_id
已设置并且我想重置它。当我在浏览器中执行此操作时,一切正常。当我尝试通过 Django TestCase 执行此操作时,它失败了,因为此会话变量未传递给请求!
class SetCategoryFilterTest(TestCase):
def setUp(self) -> None:
super().setUp()
self.fake = Faker()
self.user = User.objects.create_user(username="testuser", password="12345")
self.client.force_login(self.user)
def tearDown(self):
self.client.logout()
# ...
def test_unset_successfully(self):
"""Werify unsetting "filter_category_id" session field.
Expected: Delete "filter_category_id" when url called with parameter 0
"""
# GIVEN
session = self.client.session
session['filter_category_id'] = DUMMY_INT
session.save()
clear_arg = 0
# WHEN
self.client.get(reverse("filter_tasks_by_category", args=[clear_arg]))
# THEN
self.assertFalse("filter_category_id" in session)
如您所见,我尝试在测试中假设提到的会话变量已经设置。然后我尝试删除,但是有两个问题:
在调试过程中,条件
if 'filter_category_id' in request.session
等于False
,因此会话变量没有被取消设置。在请求完成并且代码执行回到测试用例之后,在测试用例开头设置的会话变量仍然存在,因此测试失败。
我试图遵循文档中的规则,即我们需要在修改之前将会话存储到变量并save()
在之后调用。但这没有帮助。另外,我在某处读到最好做另一个请求,或者至少login()
为了设置会话对象。但是,正如您在setUp()
方法中看到的,登录已经完成。
当我尝试执行另一个请求以确保已创建会话时,它也无济于事:
def test_unset_successfully(self):
"""Werify unsetting "filter_category_id" session field.
Expected: Delete "filter_category_id" when url called with parameter 0
"""
# GIVEN
category = Category.objects.create(user=self.user, name=self.fake.name())
self.client.get(reverse("filter_tasks_by_category", args=[category.id]))
session = self.client.session
session['filter_category_id'] = DUMMY_INT
session.save()
clear_arg = 0
# WHEN
self.client.get(reverse("filter_tasks_by_category", args=[clear_arg]))
# THEN
self.assertFalse("filter_category_id" in session)
这段代码不仅奇怪,而且没有确认访问会话对象之前必须先请求的语句。
你知道如何处理这种情况吗?基本上我想做的就是设置一个会话变量并将其与请求一起传递给我的视图。
解决方案
如果您只想测试删除部分,请使用模拟:
def test_unset_successfully(self):
request_mock = Mock()
request_mock.session = {"filter_category_id": 123}
set_category_filter(request_mock, 0)
self.assertIsNone(request_mock.session.get("filter_category_id"))
推荐阅读
- db2 - 更正我遇到错误的 DB2 查询
- javascript - Draftable.com API 在 Google App Script 中传递 JSON 时给出截断响应
- c# - 如何在 C# 的泛型函数中传递类型
- c++ - 具有默认构造函数的类的成员是否零初始化?
- java - 解决方案中的重复计划实体
- go - 在 Go 中创建一个并行单词计数器
- node.js - azure blob storage nodejs v10 - 应用程序抛出未捕获的异常并终止
- c# - Exception: DataAnalysis.Reference+<>c__DisplayClass4 is not serializable
- javascript - 有没有办法在按下按钮后更改表单两次选择(两次选择)的动作?
- reactive-programming - Spring Data Couchbase 反应式是否支持分页?