如何在测试期间将 Django 视图 GET 请求的响应插入到与 POST 请求相同的视图中?
How to plug the reponse of a django view GET request into the same view as a POST request during testing?
我有一个基于 Django 函数的表单视图,它在 GET 请求中使用默认数据初始化表单,并在 POST 请求中保存模型对象:
def copy(request, ann_id):
new_ann = get_object_or_404(Announcement, pk=ann_id)
new_ann.pk = None # autogen a new primary key (quest_id by default)
new_ann.title = "Copy of " + new_ann.title
new_ann.draft = True
new_ann.datetime_released = new_ann.datetime_released + timedelta(days=7)
form = AnnouncementForm(request.POST or None, instance=new_ann)
if form.is_valid():
new_announcement = form.save(commit=False)
new_announcement.author = request.user
new_announcement.datetime_created = timezone.now()
new_announcement.save()
form.save()
return redirect(new_announcement)
context = {
"title": "",
"heading": "Copy an Announcement",
"form": form,
"submit_btn_value": "Create",
}
return render(request, "announcements/form.html", context)
在我看来,如果不手动向 self.client.post(url, form_data)
提供表单数据,我不知道如何在发布表单时测试 form.is_valid()
分支。
这是我正在尝试的:
test_views.py
class AnnouncementViewTests(TestCase):
def setUp(self):
self.client = ...
... etc
def test_copy_announcement(self):
# log in a teacher
success = self.client.login(username=self.test_teacher.username, password=self.test_password)
self.assertTrue(success)
# hit the view as a get request first, to load a copy of the announcement in the form
response = self.client.get(
reverse('announcements:copy', args=[self.test_announcement.id]),
)
self.assertEqual(response.status_code, 200)
# The form in this response should be valid, and should bw
# accepted on a post request,
# that is what I am testing in this integration test.
form_data = response.how_do_get_the_form_data() # ???????
response = self.client.post(
reverse('announcements:copy', args=[self.test_announcement.id]),
data=form_data
)
# Get the newest announcement just made in the post request
new_ann = Announcement.objects.latest('datetime_created')
self.assertRedirects(
response,
new_ann.get_absolute_url()
)
我想实际测试的是 get
的结果为表单提供了有效的默认数据,然后可以通过 post
请求提交。
但我不知道如何访问 get
请求产生的表单数据,所以我可以将它提供给 post
请求的 form_data .
编辑
我在获取响应中找到了表单的位置,但我不知道如何在代码中获取它。
您的问题有点令人困惑,但我会尽力为您指明正确的方向。
要清理代码,您应该使用 Class 基于视图,您可以在其中轻松地在任何地方使用您的表单。我刚刚写的示例代码:
class TestView(View):
template_name = 'index.html'
success_url = 'home' # dummy view
context = {"form": myform()}
# myform is the definition/class of your form which contains all attrs.
def get(self, request):
context = self.context
context['form'] = form # fill out your data here for get request
return render(request, self.template_name, context)
def post(self, request):
context=self.context
# self.context certain that you're using exact form which you defined in class-scope
form=context['form']
# Form Validation
if form.is_valid():
#perform any logical validations here and save the form if required
return redirect(self.success_url)
context = self.context
context['form'] = form # just to show you that you can access that form anywhere
return render(request, self.template_name, context)
您可以像这样手动将数据传递给您的表单并在单元测试中测试 is_valid
函数:
form_data = {'my': 'value', 'form': 'value', 'fields': 'value'}
form = AnnouncementForm(form_data)
self.assertFalse(form.is_valid)
您可以通过以下方式访问回复表单:
response.context['form']
从这里您可以通过以下方式构建您的负载:
retrieved_instance = response.context['form'].instance
form_data = dict(title=retrieved_instance.title, ... <all the other fields>)
response = self.client.post(
reverse('announcements:copy', args=[self.test_announcement.id]),
data=form_data)
)
这与重新提交页面不同,但非常相似,因为您要重新提交相同的表单。
实际上,您的测试看起来更像是一个 e2e 测试(在谈到集成和 e2e 时,可以说有些歧义),因此,如果我是您,我会切换 "tool" 并使用 selenium模拟从开始(打开现有公告)到结束的用户交互,按下网页上的提交按钮。
只有这样,您提交的才是 "get"
的 "real" 响应
如果您是这种测试的新手,可以在这里找到一个简单的教程https://lincolnloop.com/blog/introduction-django-selenium-testing/来理解主要概念。
我有一个基于 Django 函数的表单视图,它在 GET 请求中使用默认数据初始化表单,并在 POST 请求中保存模型对象:
def copy(request, ann_id):
new_ann = get_object_or_404(Announcement, pk=ann_id)
new_ann.pk = None # autogen a new primary key (quest_id by default)
new_ann.title = "Copy of " + new_ann.title
new_ann.draft = True
new_ann.datetime_released = new_ann.datetime_released + timedelta(days=7)
form = AnnouncementForm(request.POST or None, instance=new_ann)
if form.is_valid():
new_announcement = form.save(commit=False)
new_announcement.author = request.user
new_announcement.datetime_created = timezone.now()
new_announcement.save()
form.save()
return redirect(new_announcement)
context = {
"title": "",
"heading": "Copy an Announcement",
"form": form,
"submit_btn_value": "Create",
}
return render(request, "announcements/form.html", context)
在我看来,如果不手动向 self.client.post(url, form_data)
提供表单数据,我不知道如何在发布表单时测试 form.is_valid()
分支。
这是我正在尝试的:
test_views.py
class AnnouncementViewTests(TestCase):
def setUp(self):
self.client = ...
... etc
def test_copy_announcement(self):
# log in a teacher
success = self.client.login(username=self.test_teacher.username, password=self.test_password)
self.assertTrue(success)
# hit the view as a get request first, to load a copy of the announcement in the form
response = self.client.get(
reverse('announcements:copy', args=[self.test_announcement.id]),
)
self.assertEqual(response.status_code, 200)
# The form in this response should be valid, and should bw
# accepted on a post request,
# that is what I am testing in this integration test.
form_data = response.how_do_get_the_form_data() # ???????
response = self.client.post(
reverse('announcements:copy', args=[self.test_announcement.id]),
data=form_data
)
# Get the newest announcement just made in the post request
new_ann = Announcement.objects.latest('datetime_created')
self.assertRedirects(
response,
new_ann.get_absolute_url()
)
我想实际测试的是 get
的结果为表单提供了有效的默认数据,然后可以通过 post
请求提交。
但我不知道如何访问 get
请求产生的表单数据,所以我可以将它提供给 post
请求的 form_data .
编辑
我在获取响应中找到了表单的位置,但我不知道如何在代码中获取它。
您的问题有点令人困惑,但我会尽力为您指明正确的方向。
要清理代码,您应该使用 Class 基于视图,您可以在其中轻松地在任何地方使用您的表单。我刚刚写的示例代码:
class TestView(View):
template_name = 'index.html'
success_url = 'home' # dummy view
context = {"form": myform()}
# myform is the definition/class of your form which contains all attrs.
def get(self, request):
context = self.context
context['form'] = form # fill out your data here for get request
return render(request, self.template_name, context)
def post(self, request):
context=self.context
# self.context certain that you're using exact form which you defined in class-scope
form=context['form']
# Form Validation
if form.is_valid():
#perform any logical validations here and save the form if required
return redirect(self.success_url)
context = self.context
context['form'] = form # just to show you that you can access that form anywhere
return render(request, self.template_name, context)
您可以像这样手动将数据传递给您的表单并在单元测试中测试 is_valid
函数:
form_data = {'my': 'value', 'form': 'value', 'fields': 'value'}
form = AnnouncementForm(form_data)
self.assertFalse(form.is_valid)
您可以通过以下方式访问回复表单:
response.context['form']
从这里您可以通过以下方式构建您的负载:
retrieved_instance = response.context['form'].instance
form_data = dict(title=retrieved_instance.title, ... <all the other fields>)
response = self.client.post(
reverse('announcements:copy', args=[self.test_announcement.id]),
data=form_data)
)
这与重新提交页面不同,但非常相似,因为您要重新提交相同的表单。
实际上,您的测试看起来更像是一个 e2e 测试(在谈到集成和 e2e 时,可以说有些歧义),因此,如果我是您,我会切换 "tool" 并使用 selenium模拟从开始(打开现有公告)到结束的用户交互,按下网页上的提交按钮。
只有这样,您提交的才是 "get"
的 "real" 响应如果您是这种测试的新手,可以在这里找到一个简单的教程https://lincolnloop.com/blog/introduction-django-selenium-testing/来理解主要概念。