Django 教程 10: 测试 Django 网页应用 您所在的位置:网站首页 多视图聚类的应用 Django 教程 10: 测试 Django 网页应用

Django 教程 10: 测试 Django 网页应用

2023-05-26 20:10| 来源: 网络整理| 查看: 265

为了验证我们的视图行为,我们使用 Django 的测试客户端。这个类,就像一个虚拟的 Web 浏览器,我们可以使用它,来模拟 URL 上的GET和POST请求,并观察响应。我们几乎可以看到,关于响应的所有内容,从低层级的 HTTP(结果标头和状态代码),到我们用来呈现 HTML 的模板,以及我们传递给它的上下文数据。我们还可以看到重定向链(如果有的话),并在每一步检查 URL,和状态代码。这允许我们验证每个视图,是否正在执行预期的操作。

让我们从最简单的视图开始,它提供了所有作者的列表。它显示在 URL /catalog/authors/ 当中(URL 配置中,名为“authors”的 URL)。

class AuthorListView(generic.ListView): model = Author paginate_by = 10

由于这是一个通用列表视图,几乎所有内容,都由 Django 为我们完成。可以说,如果您信任 Django,那么您唯一需要测试的,是视图可以通过正确的 URL 访问,并且可以使用其名称进行访问。但是,如果您使用的是测试驱动的开发过程,则首先编写测试,确认视图显示所有作者,并将其分成 10 个。

打开 /catalog/tests/test_views.py 文件,并用AuthorListView的以下测试代码,替换任何现有文本。和以前一样,我们导入模型,和一些有用的类。在setUpTestData()方法中,我们设置了许多Author对象,以便我们可以测试我们的分页。

from django.test import TestCase # Create your tests here. from catalog.models import Author from django.urls import reverse class AuthorListViewTest(TestCase): @classmethod def setUpTestData(cls): #Create 13 authors for pagination tests number_of_authors = 13 for author_num in range(number_of_authors): Author.objects.create(first_name='Christian %s' % author_num, last_name = 'Surname %s' % author_num,) def test_view_url_exists_at_desired_location(self): resp = self.client.get('/catalog/authors/') self.assertEqual(resp.status_code, 200) def test_view_url_accessible_by_name(self): resp = self.client.get(reverse('authors')) self.assertEqual(resp.status_code, 200) def test_view_uses_correct_template(self): resp = self.client.get(reverse('authors')) self.assertEqual(resp.status_code, 200) self.assertTemplateUsed(resp, 'catalog/author_list.html') def test_pagination_is_ten(self): resp = self.client.get(reverse('authors')) self.assertEqual(resp.status_code, 200) self.assertTrue('is_paginated' in resp.context) self.assertTrue(resp.context['is_paginated'] == True) self.assertTrue( len(resp.context['author_list']) == 10) def test_lists_all_authors(self): #Get second page and confirm it has (exactly) remaining 3 items resp = self.client.get(reverse('authors')+'?page=2') self.assertEqual(resp.status_code, 200) self.assertTrue('is_paginated' in resp.context) self.assertTrue(resp.context['is_paginated'] == True) self.assertTrue( len(resp.context['author_list']) == 3)

所有测试,都使用客户端(属于我们的TestCase的派生类)来模拟GET请求,并获得响应(resp)。第一个版本检查特定 URL(注意,只是没有域名的特定路径),而第二个版本从 URL 配置中的名称生成 URL。

resp = self.client.get('/catalog/authors/') resp = self.client.get(reverse('authors'))

获得响应后,我们会查询其状态代码,使用的模板,响应是否已分页,返回的项目数以及项目总数。

我们在上面演示的最有趣的变量是resp.context,它是视图传递给模板的上下文变量。这对测试非常有用,因为它允许我们确认模板正在获取所需的所有数据。换句话说,我们可以检查是否正在使用预期的模板,以及模板获得的数据,这对于验证任何渲染问题,是否真的仅仅归因于模板有很大帮助。

仅限登录用户的视图

在某些情况下,您需要测试仅限登录用户的视图。例如,我们的LoanedBooksByUserListView与我们之前的视图非常相似,但仅供登录用户使用,并且仅显示当前用户借用的BookInstance记录,具有出借中“on loan”状态,并且排序方式为“旧的优先”。

from django.contrib.auth.mixins import LoginRequiredMixin class LoanedBooksByUserListView(LoginRequiredMixin,generic.ListView): """ Generic class-based view listing books on loan to current user. """ model = BookInstance template_name ='catalog/bookinstance_list_borrowed_user.html' paginate_by = 10 def get_queryset(self): return BookInstance.objects.filter(borrower=self.request.user).filter(status__exact='o').order_by('due_back')

将以下测试代码,添加到 /catalog/tests/test_views.py。这里我们首先使用SetUp()创建一些用户登录帐户,和BookInstance对象(以及它们的相关书本,和其他记录),我们稍后将在测试中使用它们。每个测试用户都借用了一半的书本,但我们最初,将所有书本的状态设置为“维护”。我们使用了SetUp()而不是setUpTestData(),因为我们稍后会修改其中的一些对象。

备注: 下面的setUp()代码,会创建一个具有指定语言Language的书本,但您的代码可能不包含语言模型Language,因为它是作为挑战创建的。如果是这种情况,只需注释掉创建或导入语言对象的代码部分。您还应该在随后的RenewBookInstancesViewTest部分中,执行此操作。

import datetime from django.utils import timezone from catalog.models import BookInstance, Book, Genre, Language from django.contrib.auth.models import User #Required to assign User as a borrower class LoanedBookInstancesByUserListViewTest(TestCase): def setUp(self): #Create two users test_user1 = User.objects.create_user(username='testuser1', password='12345') test_user1.save() test_user2 = User.objects.create_user(username='testuser2', password='12345') test_user2.save() #Create a book test_author = Author.objects.create(first_name='John', last_name='Smith') test_genre = Genre.objects.create(name='Fantasy') test_language = Language.objects.create(name='English') test_book = Book.objects.create(title='Book Title', summary = 'My book summary', isbn='ABCDEFG', author=test_author, language=test_language) # Create genre as a post-step genre_objects_for_book = Genre.objects.all() test_book.genre.set(genre_objects_for_book) #Direct assignment of many-to-many types not allowed. test_book.save() #Create 30 BookInstance objects number_of_book_copies = 30 for book_copy in range(number_of_book_copies): return_date= timezone.now() + datetime.timedelta(days=book_copy%5) if book_copy % 2: the_borrower=test_user1 else: the_borrower=test_user2 status='m' BookInstance.objects.create(book=test_book,imprint='Unlikely Imprint, 2016', due_back=return_date, borrower=the_borrower, status=status) def test_redirect_if_not_logged_in(self): resp = self.client.get(reverse('my-borrowed')) self.assertRedirects(resp, '/accounts/login/?next=/catalog/mybooks/') def test_logged_in_uses_correct_template(self): login = self.client.login(username='testuser1', password='12345') resp = self.client.get(reverse('my-borrowed')) #Check our user is logged in self.assertEqual(str(resp.context['user']), 'testuser1') #Check that we got a response "success" self.assertEqual(resp.status_code, 200) #Check we used correct template self.assertTemplateUsed(resp, 'catalog/bookinstance_list_borrowed_user.html')

要验证如果用户未登录,视图将重定向到登录页面,我们使用assertRedirects,如test_redirect_if_not_logged_in()中所示。要验证是否已为登录用户显示该页面,我们首先登录我们的测试用户,然后再次访问该页面,并检查我们获得的status_code为 200(成功)。

测试的其余部分,验证我们的观点,仅返回借给当前借用人的书本。复制上面测试类末尾的(自解释)代码。

def test_only_borrowed_books_in_list(self): login = self.client.login(username='testuser1', password='12345') resp = self.client.get(reverse('my-borrowed')) #Check our user is logged in self.assertEqual(str(resp.context['user']), 'testuser1') #Check that we got a response "success" self.assertEqual(resp.status_code, 200) #Check that initially we don't have any books in list (none on loan) self.assertTrue('bookinstance_list' in resp.context) self.assertEqual( len(resp.context['bookinstance_list']),0) #Now change all books to be on loan get_ten_books = BookInstance.objects.all()[:10] for copy in get_ten_books: copy.status='o' copy.save() #Check that now we have borrowed books in the list resp = self.client.get(reverse('my-borrowed')) #Check our user is logged in self.assertEqual(str(resp.context['user']), 'testuser1') #Check that we got a response "success" self.assertEqual(resp.status_code, 200) self.assertTrue('bookinstance_list' in resp.context) #Confirm all books belong to testuser1 and are on loan for bookitem in resp.context['bookinstance_list']: self.assertEqual(resp.context['user'], bookitem.borrower) self.assertEqual('o', bookitem.status) def test_pages_ordered_by_due_date(self): #Change all books to be on loan for copy in BookInstance.objects.all(): copy.status='o' copy.save() login = self.client.login(username='testuser1', password='12345') resp = self.client.get(reverse('my-borrowed')) #Check our user is logged in self.assertEqual(str(resp.context['user']), 'testuser1') #Check that we got a response "success" self.assertEqual(resp.status_code, 200) #Confirm that of the items, only 10 are displayed due to pagination. self.assertEqual( len(resp.context['bookinstance_list']),10) last_date=0 for copy in resp.context['bookinstance_list']: if last_date==0: last_date=copy.due_back else: self.assertTrue(last_date


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有