Django單元測(cè)試工具test client使用詳解
The test client
test client是一個(gè)python類,來模擬一個(gè)簡(jiǎn)單的“啞”瀏覽器,允許你來測(cè)試你的view函數(shù).你可以使用test client完成下列事情:
1.模擬"Get"和"Post"請(qǐng)求,觀察響應(yīng)結(jié)果--從HTTP(headers,status codes)到頁(yè)面內(nèi)容.
2.檢查重定向鏈(如果有的話),在每一步檢查URL和status code。
3.用一個(gè)包括特定值的模板context來測(cè)試一個(gè)request被Django模板渲染。
>>> from django.test.client import Client >>> c = Client() >>> response = c.post('/login/', {'username': 'john', 'password': 'smith'}) >>> response.status_code 200 >>> response = c.get('/customer/details/') >>> response.content '<!DOCTYPE html...'
使用django.test.client.Client的實(shí)例來使用test client。
注意:請(qǐng)求網(wǎng)頁(yè)時(shí),使用path而不是整個(gè)domain。
>>> c.get('/login/')
是正確的。
>>> c.get('http://www.example.com/login/')
是錯(cuò)誤的。
test client不適合操作不是由Django建立的網(wǎng)站.所以,請(qǐng)求其它網(wǎng)頁(yè)時(shí),請(qǐng)使用python的標(biāo)準(zhǔn)庫(kù)--urllib或者urllib2.
為了解析URl,test client使用由ROOT_URLCONF(settings.py)指定的URLconf。
默認(rèn)情況下,test client會(huì)忽略CSRF檢查,如果要強(qiáng)制進(jìn)行CSRF檢查,可以
csrf_client = Client(enforce_csrf_checks=True)
Making Requests
使用django.test.client.Client()來執(zhí)行請(qǐng)求。
class Client(enforce_csrf_checks=False, **defaults)
可以使用關(guān)鍵字參數(shù)來指定默認(rèn)的請(qǐng)求報(bào)頭:
c = Client(HTTP_USER_AGENT='Mozilla/5.0')
記得在USER_AGENT前加HTTP_。
Client實(shí)例具有以下方法:
get(path, data={}, follow=False, **extra)
執(zhí)行一個(gè)GET請(qǐng)求并返回Response對(duì)象。
>>> c = Client() >>> c.get('/customers/details/', {'name': 'fred', 'age': 7})
相當(dāng)于向以下url執(zhí)行GET:
/customers/details/?name=fred&age=7
extra關(guān)鍵字參數(shù)可用作請(qǐng)求報(bào)頭:
>>> c = Client() >>> c.get('/customers/details/', {'name': 'fred', 'age': 7}, ... HTTP_X_REQUESTED_WITH='XMLHttpRequest')
當(dāng)然也可以將查詢字符對(duì)編碼后加入url:
>>> c = Client() >>> c.get('/customers/details/?name=fred&age=7')
data參數(shù)的優(yōu)先級(jí)在編碼后的url之上。
如果將follow設(shè)置為True,client會(huì)追蹤任何重定向,返回的response有redirect_chain屬性,包括所有重定向過程中的url和狀態(tài)碼組成的元祖列表。
如果有個(gè)URL /redirect_me/ 重定向向 /next/, 再重定向向 /final/:
>>> response = c.get('/redirect_me/', follow=True) >>> response.redirect_chain [(u'http://testserver/next/', 302), (u'http://testserver/final/', 302)]
post(path, data={}, content_type=MULTIPART_CONTENT, follow=False, **extra)
執(zhí)行一個(gè)POST請(qǐng)求并返回response對(duì)象,data參數(shù)為POST數(shù)據(jù)。
如果提供content_type參數(shù)(例如 text/xml),數(shù)據(jù)會(huì)被作為報(bào)頭中Content-Type的類型進(jìn)行POST上傳。
如果不提供content_type參數(shù),數(shù)據(jù)會(huì)被作為multipart/form-data類型上傳。
為一個(gè)參數(shù)提交多個(gè)多個(gè)值時(shí)--比如選住<select multiple>域的多個(gè)值--這些值可以是列表或者元組.舉例來說,提交choice域的三個(gè)被選中的值:
{'choices': ('a', 'b', 'd')}
上傳文件:
>>> c = Client() >>> with open('wishlist.doc') as fp: ... c.post('/customers/wishes/', {'name': 'fred', 'attachment': fp})
文件的名字'attachment'是不相關(guān)的,取決于你處理文件的代碼。
如果同一個(gè)文件要post多次,注意每次post都要恢復(fù)文件的指針,最簡(jiǎn)單的方法就是將文件關(guān)閉再重新打開。
注意文件要以正確的方式被打開以便于讀取,如果文件是binary data,例如讀取img時(shí),要將打開模式設(shè)為rb。
post的路徑中也可以包含查詢字符對(duì):
>>> c.post('/login/?visitor=true', {'name': 'fred', 'passwd': 'secret'})
這樣既會(huì)通過post上傳data數(shù)據(jù),也向GET確定visitor=True。
options(path, data='', content_type='application/octet-stream', follow=False, **extra)
做OPTIONS請(qǐng)求,對(duì)測(cè)試REST接口很有用。data被用作請(qǐng)求的主體。
put(path, data='', content_type='application/octet-stream', follow=False, **extra)
做PUT請(qǐng)求,測(cè)試RESTful接口。
patch(path, data='', content_type='application/octet-stream', follow=False, **extra)
做PATCH請(qǐng)求,測(cè)試RESTful接口。
delete(path, data='', content_type='application/octet-stream', follow=False, **extra)
做DELETE請(qǐng)求,測(cè)試RESTful接口。
login(**credentials)
如果使用django的用戶驗(yàn)證系統(tǒng),可用login方法進(jìn)行測(cè)試。
>>> c = Client() >>> c.login(username='fred', password='secret')
登陸成功的話,返回True。
使用之前,當(dāng)然要?jiǎng)?chuàng)建一個(gè)用戶。由于測(cè)試數(shù)據(jù)庫(kù)使用的是單獨(dú)的數(shù)據(jù)庫(kù),原先數(shù)據(jù)庫(kù)中的用戶是不能用于測(cè)試的。
設(shè)置密碼時(shí),不能用user的密碼屬性進(jìn)行設(shè)置,而是用set_password()方法設(shè)置正確的哈希密碼,或者使用create_user()方法創(chuàng)建一個(gè)帶哈希密碼的用戶。
logout()
登出。
Testing Responses
client的get和post方法都返回response對(duì)象,和HttpResponse對(duì)象是不同的。
class Response具有以下屬性:
client:the test client
content:response的主體,string類型,是view render后的頁(yè)面的最終內(nèi)容,或者是錯(cuò)誤信息。
context:用來渲染模板的context實(shí)例。如果頁(yè)面使用了多個(gè)模板,那context就會(huì)是Context Object列表.它們的排序方式就是它們被渲染的順序。
>>> response = client.get('/foo/') >>> response.context['name'] 'Arthur'
request:用于請(qǐng)求的數(shù)據(jù)。
status_code:狀態(tài)碼。
templates:被用來渲染最終的content的Template實(shí)例列表.template.name可以得到template的文件名,如果template是由文件載入的話(如 'admin/index.html')。那template就會(huì)是Template列表,它們的排序方式就是它們被渲染的順序.
response也可以當(dāng)做字典來查詢Http header:
response['Content-Type']
Exceptions
如果你將TestClient指向了由view函數(shù)raise的異常,那這個(gè)異常在test case里是可見的.你可以使用標(biāo)準(zhǔn)的try...except塊或者assertRaises()來測(cè)試它們.對(duì)test client唯一不可見的異常是Http404,PermissionDenied和SystemExit。django會(huì)在內(nèi)部捕捉這些異常并返回合適的response.這種情況下,你可以查看下你的response.status_code.
Persistent state
如果一個(gè)response返回了一個(gè)cookie,那么這個(gè)cookie就會(huì)被存儲(chǔ)在test client里,并被其后的所有g(shù)et()和post()傳送.如果你想要終止這個(gè)cookie,你可以新建一個(gè)Client實(shí)例,或者手動(dòng)刪除它。
一個(gè)test client具有兩個(gè)存儲(chǔ)持久化狀態(tài)信息的屬性:
Client.cookies
一個(gè)python SimpleCookie對(duì)象,存儲(chǔ)cilent的所有cookie。
Client.sessions
包含session信息的類字典對(duì)象。
如果要修改一個(gè)session并且存儲(chǔ),首先將session存儲(chǔ)在變量中:
def test_something(self): session = self.client.session session['somekey'] = 'test' session.save()
一個(gè)使用client進(jìn)行測(cè)試的實(shí)例:
from django.utils import unittest from django.test.client import Client class SimpleTest(unittest.TestCase): def setUp(self): # Every test needs a client. self.client = Client() def test_details(self): # Issue a GET request. response = self.client.get('/customer/details/') # Check that the response is 200 OK. self.assertEqual(response.status_code, 200) # Check that the rendered context contains 5 customers. self.assertEqual(len(response.context['customers']), 5)
Test cases的一些功能
默認(rèn)的test client
每個(gè)django.test.*TestCase的test case實(shí)例都會(huì)訪問django test client,所以Client可以不用實(shí)例化,而直接用self.client訪問:
from django.test import TestCase class SimpleTest(TestCase): def test_details(self): response = self.client.get('/customer/details/') self.assertEqual(response.status_code, 200) def test_index(self): response = self.client.get('/customer/index/') self.assertEqual(response.status_code, 200)
Fixture loading
如果數(shù)據(jù)庫(kù)里沒有數(shù)據(jù),那么對(duì)于一個(gè)基于數(shù)據(jù)庫(kù)的網(wǎng)站來說,test case并無多大的用處.為了給測(cè)試數(shù)據(jù)庫(kù)加入測(cè)試數(shù)據(jù)更方便,django提供了載入fixtures的方法.
fixture是一系列的數(shù)據(jù)集合,django知道如何將它導(dǎo)入數(shù)據(jù)庫(kù)。
創(chuàng)建fixture最直接的方法就是使用manage.py dumpdata.當(dāng)然,這假設(shè)你的實(shí)際數(shù)據(jù)庫(kù)里已經(jīng)有數(shù)據(jù)了.
注意:
如果你運(yùn)行過manage.py syncdb命令,那么你已經(jīng)使用過fixture了--只是你不知道而已。當(dāng)你使用syncdb去創(chuàng)建數(shù)據(jù)庫(kù)時(shí),會(huì)創(chuàng)建一個(gè)叫initial_data的fixture。
其他名字的Fixture可以通過manage.py loaddata命令手動(dòng)安裝.
一旦建立了一個(gè)fixture,并將它放在了某個(gè)django app的fixtures目錄中,你就可以在你的測(cè)試類里使用它了:
from django.test import TestCase from myapp.models import Animal class AnimalTestCase(TestCase): fixtures = ['mammals.json', 'birds'] def setUp(self): # Test definitions as before. call_setup_methods() def testFluffyAnimals(self): # A test that uses the fixtures. call_some_test_code()
這是具體發(fā)生的過程:
1. 在setup()運(yùn)行前,django會(huì)清空數(shù)據(jù)庫(kù),相當(dāng)于你執(zhí)行了syncdb。
2.然后,所有的fixture會(huì)被安裝.在例子中,django會(huì)安裝任何一個(gè)名字為mammals的JSON格式的fixture和名為birds的fixture數(shù)據(jù)。
Assertions
除了python中的assertEqual()和assertTrue()外,django的TestCase還提供了幾個(gè)額外的assert方法。
assertContains(response, text, count=None, status_code=200, msg_prefix='', html=False)
斷言response是否與status_code和text內(nèi)容相應(yīng)。將html設(shè)為True會(huì)將text作為html處理。
assertJSONEqual(raw, expected_data, msg=None)
斷言Json片段raw和expected_data是否相當(dāng)。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Python中sorted()函數(shù)之排序的利器詳解
sorted()函數(shù)是Python中的內(nèi)置函數(shù),用于對(duì)可迭代對(duì)象進(jìn)行排序,下面這篇文章主要給大家介紹了關(guān)于Python中sorted()函數(shù)之排序的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-08-08python 實(shí)現(xiàn)體質(zhì)指數(shù)BMI計(jì)算
這篇文章主要介紹了python 實(shí)現(xiàn)體質(zhì)指數(shù)BMI計(jì)算操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-05-05Python開發(fā)的十個(gè)小貼士和技巧及長(zhǎng)常犯錯(cuò)誤
這篇文章主要介紹了Python開發(fā)的十個(gè)小貼士和技巧,其中一些是初學(xué)這門語言常常會(huì)犯的錯(cuò)誤,小編給大家一一列舉出來了,需要的朋友可以參考下2018-09-09Python機(jī)器學(xué)習(xí)入門(二)之Python數(shù)據(jù)理解
這篇文章主要介紹了Python機(jī)器學(xué)習(xí)入門知識(shí),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-08-08在Python 中同一個(gè)類兩個(gè)函數(shù)間變量的調(diào)用方法
今天小編就為大家分享一篇在Python 中同一個(gè)類兩個(gè)函數(shù)間變量的調(diào)用方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-01-01python爬蟲之驗(yàn)證碼篇3-滑動(dòng)驗(yàn)證碼識(shí)別技術(shù)
本篇涉及到的驗(yàn)證碼為滑動(dòng)驗(yàn)證碼,不同于極驗(yàn)證,本驗(yàn)證碼難度略低,需要的將滑塊拖動(dòng)到矩形區(qū)域右側(cè)即可完成。對(duì)python爬蟲滑動(dòng)驗(yàn)證碼識(shí)別技術(shù)感興趣的朋友跟隨小編一起看看吧2019-04-04利用Python實(shí)現(xiàn)生成并識(shí)別圖片驗(yàn)證碼
這篇文章主要為大家的詳細(xì)介紹了如何利用Python實(shí)現(xiàn)生成并識(shí)別圖片驗(yàn)證碼,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-02-02