Diango博客--24.單元測試:測試評論應用

文章目錄

  • 1. 前言
  • 2. 數據基類
  • 3.測試 Comment Model
  • 4. 測試視圖函數
  • 5. 測試模板標簽

1. 前言

comments應用的測試和blog應用測試的套路是一樣的。

先來建立測試文件的目錄結構。首先在 comments 應用的目錄下建立一個名為 tests 的 Python 包,然后刪除 comments 應用下 django 自動生成的 tests.py 文件,防止和 tests 包沖突,再根據需要測試的內容,創建相應的 Python 模塊。最終 tests 目錄結構如下,其中 base.py 用于存放各個測試用例的公共的數據初始化基類。

在這里插入圖片描述

2. 數據基類

由于評論必須和文章關聯,因此我們首先來寫一個數據基類,用于初始化生成文章數據,其它測試類繼承這個數據基類,從而不用在每個測試類里都寫一遍創建文章數據的代碼了。數據基類寫在 base.py 模塊里:

文件位置:comments/tests/base.py


from django.apps import apps
from django.contrib.auth.models import User
from django.test import TestCasefrom blog.models import Category, Postclass CommentDataTestCase(TestCase):def setUp(self):apps.get_app_config('haystack').signal_processor.teardown()self.user = User.objects.create_superuser(username='admin',email='admin@hellogithub.com',password='admin')self.cate = Category.objects.create(name='測試')self.post = Post.objects.create(title='測試標題',body='測試內容',category=self.cate,author=self.user,)

要注意創建文章數據時,使用 apps.get_app_config(‘haystack’).signal_processor.teardown() 斷開創建索引的信號

3.測試 Comment Model

先回顧一下comments應用的models.py

from django.db import models
from django.utils import timezoneclass Comment(models.Model):name = models.CharField('名字', max_length=50)email = models.EmailField('郵箱')url = models.URLField('網址', blank=True)text = models.TextField('內容')created_time = models.DateTimeField('創建時間', default=timezone.now)post = models.ForeignKey('blog.Post', verbose_name='文章', on_delete=models.CASCADE)class Meta:verbose_name = '評論'verbose_name_plural = verbose_nameordering = ['-created_time']def __str__(self):return '{}: {}'.format(self.name, self.text[:20])

Comment Model 的代碼邏輯比較簡單,測試起來也很簡單:

文件位置:comments/tests/test_models.py


from .base import CommentDataTestCase
from ..models import Commentclass CommentModelTestCase(CommentDataTestCase):def setUp(self):super().setUp()self.comment = Comment.objects.create(name='評論者',email='a@a.com',text='評論內容',post=self.post,)def test_str_representation(self):self.assertEqual(self.comment.__str__(), '評論者: 評論內容')

4. 測試視圖函數

我們只有一個發表評論的視圖函數,首先回顧一下:

from blog.models import Post
from django.shortcuts import get_object_or_404, redirect, render
from django.views.decorators.http import require_POSTfrom .forms import CommentForm
from django.contrib import messages@require_POST
def comment(request, post_pk):# 先獲取被評論的文章,因為后面需要把評論和被評論的文章關聯起來。# 這里我們使用了 Django 提供的一個快捷函數 get_object_or_404,# 這個函數的作用是當獲取的文章(Post)存在時,則獲取;否則返回 404 頁面給用戶。post = get_object_or_404(Post, pk=post_pk)# django 將用戶提交的數據封裝在 request.POST 中,這是一個類字典對象。# 我們利用這些數據構造了 CommentForm 的實例,這樣就生成了一個綁定了用戶提交數據的表單。form = CommentForm(request.POST)# 當調用 form.is_valid() 方法時,Django 自動幫我們檢查表單的數據是否符合格式要求。if form.is_valid():# 檢查到數據是合法的,調用表單的 save 方法保存數據到數據庫,# commit=False 的作用是僅僅利用表單的數據生成 Comment 模型類的實例,但還不保存評論數據到數據庫。comment = form.save(commit=False)# 將評論和被評論的文章關聯起來。comment.post = post# 最終將評論數據保存進數據庫,調用模型實例的 save 方法comment.save()messages.add_message(request, messages.SUCCESS, '評論發表成功!', extra_tags='success')# 重定向到 post 的詳情頁,實際上當 redirect 函數接收一個模型的實例時,它會調用這個模型實例的 get_absolute_url 方法,# 然后重定向到 get_absolute_url 方法返回的 URL。return redirect(post)# 檢查到數據不合法,我們渲染一個預覽頁面,用于展示表單的錯誤。# 注意這里被評論的文章 post 也傳給了模板,因為我們需要根據 post 來生成表單的提交地址。context = {'post': post,'form': form,}messages.add_message(request, messages.ERROR, '評論發表失敗!請修改表單中的錯誤后重新提交。', extra_tags='danger')return render(request, 'comments/preview.html', context=context)

根據視圖函數的邏輯,需要測試以下幾點:

  1. 只處理 POST 請求,其它請求將返回 405 Method Not Allowed 錯誤碼。
  2. 如果評論的文章不存在,返回 404 錯誤碼。
  3. 如果提交的評論內容有錯誤(例如 email 格式不正確),將渲染 preview.html 預覽頁面,并且預覽頁面顯示評論出錯的消息提醒和評論表單中包含的錯誤。
  4. 提交的內容合法,則創建評論,用戶被重定向回被評論文章的詳情頁,頁面中包含評論成功的消息提醒。

具體代碼如下:

文件位置:comments/tests/test_views.py

from django.apps import apps
from django.contrib.auth.models import User
from django.urls import reversefrom blog.models import Category, Postfrom ..models import Comment
from .base import CommentDataTestCaseclass CommentViewTestCase(CommentDataTestCase):def setUp(self) -> None:super().setUp()self.url = reverse("comments:comment", kwargs={"post_pk": self.post.pk})def test_comment_a_nonexistent_post(self):url = reverse("comments:comment", kwargs={"post_pk": 100})response = self.client.post(url, {})self.assertEqual(response.status_code, 404)def test_invalid_comment_data(self):invalid_data = {"email": "invalid_email",}response = self.client.post(self.url, invalid_data)self.assertTemplateUsed(response, "comments/preview.html")self.assertIn("post", response.context)self.assertIn("form", response.context)form = response.context["form"]for field_name, errors in form.errors.items():for err in errors:self.assertContains(response, err)self.assertContains(response, "評論發表失敗!請修改表單中的錯誤后重新提交。")def test_valid_comment_data(self):valid_data = {"name": "評論者","email": "a@a.com","text": "評論內容",}response = self.client.post(self.url, valid_data, follow=True)self.assertRedirects(response, self.post.get_absolute_url())self.assertContains(response, "評論發表成功!")self.assertEqual(Comment.objects.count(), 1)comment = Comment.objects.first()self.assertEqual(comment.name, valid_data["name"])self.assertEqual(comment.text, valid_data["text"])
  1. 在 test_invalid_comment_data 測試用例。這個測試用例中,我們構造了一個缺失評論內容、評論人名字且郵箱格式不正確的數據,然后將其提交了評論。接著就是對預期結果的斷言。這里關鍵的一點是,渲染的預覽頁面應該包含提示用戶的表單錯誤。所以我們從響應的上下文變量中取得表單 form 這個模板變量。接著使用如下代碼獲取表單的錯誤并斷言響應中是否包含了這些錯誤:
for field_name, errors in form.errors.items():for err in errors:self.assertContains(response, err)

一旦表單綁定了數據,并且 is_valid 方法被調用,就會有一個 errors 屬性(參考評論視圖函數中表單的處理邏輯)。errors 屬性是一個類字典對象,如果表單數據不包含錯誤,則為空;如果包含錯誤數據,則其鍵為包含錯誤數據的字段名稱,值為該字段錯誤提示構成的列表(一個字段可能包含多個錯誤,所以是一個列表)。例如這里的 form.errors,如果將其打印出來(使用 print(repr(form.errors)),str 方法返回的內容是經渲染的 ul 列表),可以看到它的內容如下:

{'name': ['這個字段是必填項。'], 'email': ['輸入一個有效的 Email 地址。'], 'text': ['這個字段是必填項。']}
  1. test_valid_comment_data 中,我們構造合法的評論內容并提交,預期結果是評論提交成功后重定向到被評論文章的詳情頁,所以使用了 assertRedirects 進行斷言。
    注意 self.client.post(self.url, valid_data, follow=True) 傳入的 follow=True 參數。由于評論成功后需要重定向,因此傳入 follow=True,表示跟蹤重定向,因此返回的響應,是最終重定向之后返回的響應(即被評論文章的詳情頁),如果傳入 False,則不會追蹤重定向,返回的響應就是一個響應碼為 302 的重定向前響應。
    對于重定向響應,使用 assertRedirects 進行斷言,這個斷言方法會對重定向的整個響應的過程進行檢測,默認檢測的是響應碼從 302 變為 200。

5. 測試模板標簽

上一篇中介紹過模板標簽的測試方法。基本套路就是代替 django 視圖函數自動渲染模板內容的過程,手工構造一個包含待測試模板標簽的模板,然后手工渲染其內容,斷言渲染后的內容是否包含預期的內容。具體代碼請看源代碼,這里不再一一講解,只將涉及的幾個新的表單操作進行一個簡單介紹。

class CommentExtraTestCase(CommentDataTestCase):# ...省略其它測試用例的代碼def test_show_comment_form_with_invalid_bound_form(self):template = Template('{% load comments_extras %}''{% show_comment_form post form %}')invalid_data = {'email': 'invalid_email',}form = CommentForm(data=invalid_data)self.assertFalse(form.is_valid())context = Context(show_comment_form(self.ctx, self.post, form=form))expected_html = template.render(context)for field in form:label = '<label for="{}">{}:</label>'.format(field.id_for_label, field.label)self.assertInHTML(label, expected_html)self.assertInHTML(str(field), expected_html)self.assertInHTML(str(field.errors), expected_html)

看到循環表單 form 的語句:

for field in form:label = '<label for="{}">{}:</label>'.format(field.id_for_label, field.label)

我們這里使用了 field 的兩個屬性,id_for_label 和 id_for_label,分別是 django 表單自動生成的表單字段 label 的 id 和 label 名。別的就沒什么好說的了,就是不停地斷言頁面包含預期的 HTML 內容。

至此,我們完成了對 blog 應用和 comment 應用這兩個核心 app 的測試。現在,我們想知道的是,到底我們的測試效果怎么樣呢?測試充分嗎?測試全面嗎?還有沒有沒有測到的地方呢?

單憑肉眼觀察難以回答上面的問題,接下來我們就借助一個工具,從代碼覆蓋率的角度來檢測一下我們的測試效果究竟如何。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/452111.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/452111.shtml
英文地址,請注明出處:http://en.pswp.cn/news/452111.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

面向對象設計使用語言選擇

面向對象設計的結果既可以用面向對象語言、也可以用非面向對象語言實現。 使用面向對象語言時&#xff0c;由于語言本身充分支持面向對象概念的實現&#xff0c;因此&#xff0c;編譯程序可以自動把面向對象概念映射到目標程序中。 使用非面向對象語言編寫面向對象程序&#xf…

結合shiro 的圖形驗證碼生成

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 在做用戶登錄功能時&#xff0c;很多時候都需要驗證碼支持&#xff0c;驗證碼的目的是為了防止機器人模擬真實用戶登錄而惡意訪問&#…

利用C語言實現計算機圖像處理的方法

1&#xff0e;圖像平移 圖像平移只是改變圖像在屏幕上的位置&#xff0c;圖像本身并不發生變化。假設原圖像區域左上角坐標為(x0, y0)&#xff0c;右下角坐標為(x1, y1)&#xff0c;將圖像分別沿x和y軸平移dx和dy&#xff0c;則新圖像的左上角坐標為(x0 &#xff0b; dx, y0 &a…

E24- please install the following Perl modules before executing ./mysql_install_db

2019獨角獸企業重金招聘Python工程師標準>>> [roott-cet7 scripts]# ./mysql_install_db --basedir/usr/local/mysql/ --datadir/app/data/ --usermysql FATAL ERROR: please install the following Perl modules before executing ./mysql_install_db: Data::Dumpe…

SpringMVC異常報406 (Not Acceptable)的解決辦法

使用SpsringMVC&#xff0c;使用restEasy調試&#xff0c;controller請求設置如下&#xff1a; Java代碼 RequestMapping(value"/list",methodRequestMethod.GET,producesMediaType.APPLICATION_JSON_VALUE) ResponseBody public List<EditTimeout> list()…

Diango博客--25.使用Coverage統計測試覆蓋率

文章目錄1. 前言2. 安裝 Coverage3. 簡單配置 Coverage4. 運行 Coverage5. 完善 Coverage 配置6. 生成 HTML 報告7. 完善單元測試1. 前言 我們完成了對 blog 應用和 comment 應用這兩個核心 app 的測試。現在我們想知道的是究竟測試效果怎么樣呢&#xff1f;測試充分嗎&#x…

面向對象語言的優點

1.一致的表達方法 從前面章節的講述中可以知道&#xff0c;面向對象開發基于不隨時間變化的、一致的表示方法。這種表示方法應該從問題域到OOA&#xff0c;從OOA到OOD&#xff0c;最后從OOD到面向對象編程(OOP)&#xff0c;始終穩定不變。 一致的表示方法&#xff1a; 既有利…

最好的英文詞典

辭典對于學外語的作用&#xff0c;怎么強調也不過分。經常接觸英語的人都知道&#xff0c;遇到生詞不可怕&#xff0c;可怕的是遇到認識的單詞&#xff0c;又不明白這句話什么意思。這個時候&#xff0c;辭典的作用就發揮出來了。 今天一位朋友問我一句英文的意思&#xff0c;…

oracle用戶創建及權限設置

權限&#xff1a; create session create table unlimited tablespace connect resource dba 例&#xff1a; #sqlplus /nolog SQL> conn / as sysdba; SQL>create user username identified by password SQL> grant dba to username; SQL> conn username/password…

Android動畫之逐幀動畫(FrameAnimation)詳解

今天我們就來學習逐幀動畫,廢話少說直接上效果圖如下: 幀動畫的實現方式有兩種&#xff1a; 一、在res/drawable文件夾下新建animation-list的XML實現幀動畫 1、首先在res/drawable文件夾下添加img00-img24共25張圖片 2、新建frame_anim.xml [html] view plaincopy <?xml v…

ajax-簡單參數方法實現陰影效果

注&#xff1a; 簡單參數 &#xff08;按照參數的數量和位置傳遞參數&#xff09; 使用時按照位置、數量傳遞 shadow.js函數//簡單參數實現方式/** slices:陰影* opacity:透明度* zIndex:層級* */jQuery.fn.shadow_simple function (slices,opacity,zIndex) { //獲取到每個…

第一二三范式的簡單理解

第一范式&#xff08;無重復的列&#xff09; 定義&#xff1a;數據庫表的每一列都是不可分割的原子數據項&#xff0c;而不能是集合&#xff0c;數組&#xff0c;記錄等非原子數據項。如果實體中的某個屬性有多個值時&#xff0c;必須拆分為不同的屬性 通俗解釋&#xff1a;一…

網絡爬蟲--1.通用爬蟲和聚焦爬蟲

文章目錄一.前言二.通用爬蟲1.工作原理2.通用爬蟲的局限性三.聚焦爬蟲一.前言 根據使用場景&#xff0c;網絡爬蟲可分為 通用爬蟲 和 聚焦爬蟲 兩種。 其中通用網絡爬蟲是捜索引擎抓取系統&#xff08;Baidu、Google、Yahoo等&#xff09;的重要組成部分。主要目的是將互聯網…

敏捷教練的工具箱

學習并不是簡簡單單的閱讀和瀏覽&#xff0c;而是一個積累的過程&#xff0c;一個通過持續的學習&#xff0c;對自己的知識體系不斷豐富、索引的過程。接下來我會從四個方面入手分享我的經驗。 高質量的信息源和高效的學習 Google是一個很好的工具&#xff0c;通過它&#x…

log4j教程

詳細的Log4j使用教程 轉載 2016年08月19日 14:44:49 5072 日志是應用軟件中不可缺少的部分&#xff0c;Apache的開源項目log4j是一個功能強大的日志組件,提供方便的日志記錄。在apache網站&#xff1a;jakarta.apache.org/log4j 可以免費下載到Log4j最新版本的軟件包。…

BC范式介紹

設關系模式R<U&#xff0c;F>∈1NF&#xff0c;如果對于R的每個函數依賴X→Y&#xff0c;若Y不屬于X&#xff0c;則X必含有候選碼&#xff0c;那么R∈BCNF。 即為&#xff1a;對于關系模式R&#xff0c;若 R為第一范式&#xff0c;且每個屬性都不部分依賴于候選鍵也不傳遞…

com.jhlabs:imaging:jar:01012005 所在倉庫+captcha驗證碼maven依賴

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 <repositories> <repository> <id>atlassian</id> <name>atlassian</name&g…

python 發送郵件的兩種方式【終極篇】

python 發送郵件的兩種方式【終極篇】 一&#xff0c;利用python自帶的庫 smtplib簡單高效 from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.header import Header import smtplib from django.conf import settingsmail_hos…

網絡爬蟲--2.HTTP和HTTPS

文章目錄一.簡介二.HTTP的請求與響應三.客戶端HTTP請求1.格式2.請求方法四.常用的請求報頭1.Host (主機和端口號)2.Connection (鏈接類型)3.Upgrade-Insecure-Requests (升級為HTTPS請求)4. User-Agent (瀏覽器名稱)5. Accept (傳輸文件類型)6.Referer (頁面跳轉處)7.Accept-En…

解決win7的outlook打不開的問題

outlook打不開&#xff0c;一直顯示正在處理 解決方法&#xff1a; 1. 按住Ctrl,雙擊打開組件&#xff0c;會提示是否進入安全模式&#xff0c; 進入安全模式 2. 單擊Outlook中的文件-選項-加載項- 左下角的“COM加載項“ 旁邊的“轉到”&#xff0c;將所有加載項前面的勾都去掉…