Django4.0 測(cè)試工具-測(cè)試客戶端

2022-03-17 10:29 更新

測(cè)試客戶端是一個(gè) Python 類,它充當(dāng)虛擬 Web 瀏覽器,允許您測(cè)試視圖并以編程方式與 Django 驅(qū)動(dòng)的應(yīng)用程序交互。

你可以使用測(cè)試客戶端執(zhí)行以下操作:

  • 模擬 URL 上的 ?GET? 和 ?POST ?請(qǐng)求并觀察響應(yīng)——從低級(jí) HTTP(結(jié)果頭和狀態(tài)碼)到頁面內(nèi)容,應(yīng)有盡有。
  • 查看重定向鏈(如果有的話),并檢查每個(gè)步驟的 URL 和狀態(tài)碼。
  • 測(cè)試給定的請(qǐng)求是否由給定的包含某些值以及模板上下文的 Django 模板渲染。

請(qǐng)注意,測(cè)試客戶端并不是要取代 ?Selenium? 或其他“瀏覽器內(nèi)”框架。Django 的測(cè)試客戶端有不同的側(cè)重點(diǎn)。簡(jiǎn)而言之:

  • 使用 Django 的測(cè)試客戶端來確定要渲染的模板正確,并且模板已傳遞了正確的上下文數(shù)據(jù)
  • 使用 ?Selenium ?等瀏覽器內(nèi)框架來測(cè)試呈現(xiàn)的 HTML 和網(wǎng)頁的行為,即 JavaScript 功能。 Django 還為這些框架提供了特殊支持

一個(gè)全面的測(cè)試套件應(yīng)該使用這兩種測(cè)試類型的組合。

概述和一個(gè)簡(jiǎn)單的例子

要使用測(cè)試客戶端,請(qǐng)實(shí)例化 ?django.test.Client? 并檢索網(wǎng)頁:

>>> from django.test import Client
>>> c = Client()
>>> response = c.post('/login/', {'username': 'john', 'password': 'smith'})
>>> response.status_code
200
>>> response = c.get('/customer/details/')
>>> response.content
b'<!DOCTYPE html...'

如本例所示,你可以從 Python 交互式解釋器的會(huì)話中實(shí)例化 ?Client?。
請(qǐng)注意測(cè)試客戶端如何工作的一些重要事項(xiàng):

  • 測(cè)試客戶端不需要運(yùn)行 Web 服務(wù)器。 事實(shí)上,它會(huì)運(yùn)行得很好,根本沒有運(yùn)行 Web 服務(wù)器! 那是因?yàn)樗苊饬?nbsp;HTTP 的開銷,直接與 Django 框架打交道。 這有助于使單元測(cè)試快速運(yùn)行。
  • 檢索頁面時(shí),請(qǐng)記住指定 URL 的 路徑,而不是整個(gè)域。例如,這是正確的:
>>> c.get('/login/')

這是錯(cuò)誤的:

>>> c.get('https://www.example.com/login/')

測(cè)試客戶端無法檢索不是由您的 Django 項(xiàng)目提供支持的網(wǎng)頁。 如果您需要檢索其他網(wǎng)頁,請(qǐng)使用 Python 標(biāo)準(zhǔn)庫模塊,例如 ?urllib?。

  • 為了解析 URL,測(cè)試客戶端使用你的 ?ROOT_URLCONF ?設(shè)置指向的任何 ?URLconf?。
  • 盡管上面的示例可以在 Python 交互式解釋器中運(yùn)行,但測(cè)試客戶端的某些功能,尤其是與模板相關(guān)的功能,僅在測(cè)試運(yùn)行時(shí)才可用。這樣做的原因是 Django 的測(cè)試運(yùn)行器執(zhí)行了一些黑魔法,以確定給定視圖加載了哪個(gè)模板。 這種黑魔法(本質(zhì)上是在內(nèi)存中修補(bǔ) Django 的模板系統(tǒng))僅在測(cè)試運(yùn)行期間發(fā)生。
  • 默認(rèn)情況下,測(cè)試客戶端將禁用您的站點(diǎn)執(zhí)行的任何 CSRF 檢查。如果出于某種原因,您希望測(cè)試客戶端執(zhí)行 CSRF 檢查,您可以創(chuàng)建一個(gè)強(qiáng)制執(zhí)行 CSRF 檢查的測(cè)試客戶端實(shí)例。 為此,請(qǐng)?jiān)跇?gòu)建客戶端時(shí)傳入 ?enforce_csrf_checks ?參數(shù):
>>> from django.test import Client
>>> csrf_client = Client(enforce_csrf_checks=True)

發(fā)出請(qǐng)求

使用 ?django.test.Client? 類發(fā)出請(qǐng)求。

class Client(enforce_csrf_checks=False, json_encoder=DjangoJSONEncoder, **defaults)

它在構(gòu)造時(shí)不需要任何參數(shù)。然而,你可以使用關(guān)鍵字參數(shù)來指定一些默認(rèn)頭信息。例如,這將在每個(gè)請(qǐng)求中發(fā)送一個(gè) ?User-Agent? HTTP 頭:

>>> c = Client(HTTP_USER_AGENT='Mozilla/5.0')

傳遞給 ?get()?、?post()? 等方法的 ?extra? 關(guān)鍵字參數(shù)的值,優(yōu)先于傳遞給類構(gòu)造函數(shù)的默認(rèn)值。
?enforce_csrf_checks ?參數(shù)可用于測(cè)試 CSRF 保護(hù)。
?json_encoder ?參數(shù)允許為 ?post()? 中描述的 JSON 序列化設(shè)置一個(gè)自定義 JSON 編碼器。
?raise_request_exception ?參數(shù)允許控制是否在請(qǐng)求過程中引出的異常也應(yīng)該在測(cè)試中引出。默認(rèn)值為 ?True?。
一旦有了 Client 實(shí)例,就可以調(diào)用以下任何一種方法:

get(path, data=None, follow=False, secure=False, **extra)

對(duì)提供的 ?path ?上發(fā)出 ?GET ?請(qǐng)求,并返回一個(gè) ?Response ?對(duì)象,如下所述。
?data ?字典中的鍵值對(duì)用于創(chuàng)建 ?GET ?數(shù)據(jù)有效載荷。例如:

>>> c = Client()
>>> c.get('/customers/details/', {'name': 'fred', 'age': 7})

產(chǎn)生等效的 GET 請(qǐng)求:

/customers/details/?name=fred&age=7

?extra ?關(guān)鍵詞參數(shù)可以用來指定請(qǐng)求中要發(fā)送的頭信息。例如:

>>> c = Client()
>>> c.get('/customers/details/', {'name': 'fred', 'age': 7},
...       HTTP_ACCEPT='application/json')

將 HTTP 頭 ?HTTP_ACCEPT ?發(fā)送到 ?detail ?視圖,這是測(cè)試使用 ?django.http.HttpRequest.accepts()? 方法的代碼路徑的好方法。

如果你已經(jīng)有了 URL 編碼形式的 ?GET ?參數(shù),你可以使用該編碼代替使用數(shù)據(jù)參數(shù)。例如,之前的 ?GET ?請(qǐng)求也可以改成:

>>> c = Client()
>>> c.get('/customers/details/?name=fred&age=7')

如果你提供的 URL 同時(shí)包含編碼的 ?GET ?數(shù)據(jù)和數(shù)據(jù)參數(shù),數(shù)據(jù)參數(shù)將優(yōu)先。
如果將 ?follow ?設(shè)置為 ?True?,客戶端將遵循所有重定向,并且將在響應(yīng)對(duì)象中設(shè)置 ?redirect_chain ?屬性,該屬性是包含中間 URL 和狀態(tài)碼的元組。
如果你有一個(gè) URL ?/redirect_me/?,重定向到? /next/?,再重定向到 ?/final/?,這是你會(huì)看到的:

>>> response = c.get('/redirect_me/', follow=True)
>>> response.redirect_chain
[('http://testserver/next/', 302), ('http://testserver/final/', 302)]

如果你把 ?secure ?設(shè)置為 ?True?,則客戶端將模擬 HTTPS 請(qǐng)求。

post(path, data=None, content_type=MULTIPART_CONTENT, follow=False, secure=False, **extra)

在提供的 ?path ?上發(fā)出一個(gè) ?POST ?請(qǐng)求,并返回一個(gè) ?Response ?對(duì)象,如下所述。
?data ?字典中的鍵值對(duì)用于提交 ?POST ?數(shù)據(jù)。例如:

>>> c = Client()
>>> c.post('/login/', {'name': 'fred', 'passwd': 'secret'})

這將產(chǎn)生對(duì)這個(gè) URL 的 ?POST ?請(qǐng)求:

/login/

且具有此 ?POST ?數(shù)據(jù):

name=fred&passwd=secret

如果你提供 ?application/json? 為 ?content_type?,則如果 ?data ?是一個(gè)字典、列表或元組時(shí),使用 ?json.dumps()? 進(jìn)行序列化。序列化默認(rèn)是通過 ?DjangoJSONEncoder?,可以通過為 Client 提供 ?json_encoder ?參數(shù)覆蓋。這個(gè)序列化也會(huì)發(fā)生在 ?put()?、?patch()? 和 ?delete()? 請(qǐng)求中。
如果你要提供任何其他的 ?content_type ?(例如 ?text/xml? 用于 XML 有效載荷),使用HTTP ?Content-Type? 頭中的 ?content_type?,?data ?的內(nèi)容在 ?POST ?請(qǐng)求中按原樣發(fā)送。
如果你沒有為 ?content_type ?提供一個(gè)值,data 中的值將以 ?multipart/form-data? 的內(nèi)容類型進(jìn)行傳輸。在這種情況下,data 中的鍵值對(duì)將被編碼為多部分消息,并用于創(chuàng)建 ?POST ?數(shù)據(jù)有效載荷。
要為一個(gè)給定的鍵提交多個(gè)值——例如,要指定 ?<select multiple>? 的選擇——為所需鍵提供一個(gè)列表或元組的值。例如,這個(gè) ?data ?的值將為名為 ?choices ?的字段提交三個(gè)選擇值:

{'choices': ('a', 'b', 'd')}

提交文件是一種特殊情況。要 ?POST ?一個(gè)文件,你只需要提供文件字段名作為鍵,以及你想上傳的文件的文件句柄作為值。例如:

>>> c = Client()
>>> with open('wishlist.doc', 'rb') as fp:
...     c.post('/customers/wishes/', {'name': 'fred', 'attachment': fp})

這里的?attachment?可以修改成你處理代碼時(shí)想要的名稱

你也可以提供任何類似于文件的對(duì)象(例如 ?StringIO ?或 ?BytesIO?)作為文件句柄。如果你要上傳到 ?ImageField?,這個(gè)對(duì)象需要一個(gè)可以通過 ?validate_image_file_extension ?驗(yàn)證器的 ?name ?屬性。例如:

>>> from io import BytesIO
>>> img = BytesIO(b'mybinarydata')
>>> img.name = 'myimage.jpg'

請(qǐng)注意,如果你想在多次調(diào)用 ?post()? 時(shí)使用同一個(gè)文件句柄,那么你需要在兩次調(diào)用之間手動(dòng)重置文件指針。最簡(jiǎn)單的方法是在向 ?post()? 提供文件后手動(dòng)關(guān)閉文件,如上所示。
你還應(yīng)確保文件的打開方式允許數(shù)據(jù)被讀取。如果你的文件包含二進(jìn)制數(shù)據(jù),如圖像,這意味著你需要以 ?rb? (讀取二進(jìn)制)模式打開文件。
?extra ?參數(shù)的作用與 ?Client.get()? 相同。
如果你用 ?POST ?請(qǐng)求的 URL 包含編碼參數(shù),這些參數(shù)將在 ?request.GET? 數(shù)據(jù)中提供。例如,如果你要請(qǐng)求:

>>> c.post('/login/?visitor=true', {'name': 'fred', 'passwd': 'secret'})

處理這個(gè)請(qǐng)求的視圖可以詢問 ?request.POST? 來檢索用戶名和密碼,也可以詢問 ?request.GET ?來確定該用戶是否是訪客。
如果將 ?follow ?設(shè)置為 ?True?,客戶端將遵循所有重定向,并且將在響應(yīng)對(duì)象中設(shè)置 ?redirect_chain ?屬性,該屬性是包含中間 URL 和狀態(tài)碼的元組。
如果你把 ?secure ?設(shè)置為 ?True?,則客戶端將模擬 HTTPS 請(qǐng)求。

head(path, data=None, follow=False, secure=False, **extra)

在提供的 ?path ?上發(fā)出一個(gè) ?HEAD ?請(qǐng)求,并返回一個(gè) ?Response ?對(duì)象。這個(gè)方法的工作原理和 ?Client.get()? 一樣,包括 ?follow?、?secure ?和 ?extra ?參數(shù),只是它不返回消息主體。

options(path, data='', content_type='application/octet-stream', follow=False, secure=False, **extra)

在提供的 ?path ?上發(fā)出一個(gè) ?OPTIONS ?請(qǐng)求并返回一個(gè) ?Response ?對(duì)象。用于測(cè)試 RESTful 接口。
當(dāng)提供 ?data ?時(shí),它將被用作請(qǐng)求主體并且 ?Content-Type? 頭被設(shè)置為 ?content_type?。
?follow?、 ?secure ?和 ?extra ?參數(shù)的作用與 ?Client.get()? 相同。

put(path, data='', content_type='application/octet-stream', follow=False, secure=False, **extra)

在提供的 ?path ?上發(fā)出一個(gè) ?PUT ?請(qǐng)求,并返回一個(gè) ?Response ?對(duì)象。用于測(cè)試 RESTful 接口。
當(dāng)提供 ?data ?時(shí),它將被用作請(qǐng)求主體并且 ?Content-Type? 頭被設(shè)置為 ?content_type?。
?follow?、 ?secure ?和 ?extra ?參數(shù)的作用與 ?Client.get()? 相同。

patch(path, data='', content_type='application/octet-stream', follow=False, secure=False, **extra)

在提供的 ?path ?上發(fā)出一個(gè) ?PATCH ?請(qǐng)求,并返回一個(gè) ?Response ?對(duì)象。用于測(cè)試 RESTful 接口。
?follow?、 ?secure ?和 ?extra ?參數(shù)的作用與 ?Client.get()? 相同。

delete(path, data='', content_type='application/octet-stream', follow=False, secure=False, **extra)

在提供的 ?path ?上發(fā)出一個(gè) ?DELETE ?請(qǐng)求,并返回一個(gè) ?Response ?對(duì)象。用于測(cè)試 RESTful 接口。
當(dāng)提供 ?data ?時(shí),它將被用作請(qǐng)求主體并且 ?Content-Type? 頭被設(shè)置為 ?content_type?。
?follow?、 ?secure ?和 ?extra ?參數(shù)的作用與 ?Client.get() ?相同。

trace(path, follow=False, secure=False, **extra)

在提供的 ?path ?上發(fā)出一個(gè) ?TRACE ?請(qǐng)求,并返回一個(gè) ?Response ?對(duì)象。用于模擬診斷探針。
與其他請(qǐng)求方法不同,為了符合 RFC 7231#section-4.3.8 的要求,不提供 ?data ?作為關(guān)鍵字參數(shù),該 RFC 要求跟蹤請(qǐng)求不能有主體。
?follow?、 ?secure ?和 ?extra ?參數(shù)的作用與 ?Client.get()? 相同。

login(**credentials)

如果你的網(wǎng)站使用了 Django 的 認(rèn)證系統(tǒng),并且你需要處理登錄用戶的問題,你可以使用測(cè)試客戶端的 ?login()? 方法來模擬用戶登錄網(wǎng)站的效果。
調(diào)用此方法后,測(cè)試客戶端將擁有通過任何可能構(gòu)成視圖一部分的基于登錄的測(cè)試所需的所有 cookie 和會(huì)話數(shù)據(jù)。
?credentials ?參數(shù)的格式取決于你使用的 認(rèn)證后端 (這是由你的 ?AUTHENTICATION_BACKENDS ?配置)。如果你使用的是 Django 提供的標(biāo)準(zhǔn)認(rèn)證后端(?ModelBackend?),?credentials ?應(yīng)該是用戶的用戶名和密碼,并作為關(guān)鍵字參數(shù)提供:

>>> c = Client()
>>> c.login(username='fred', password='secret')

# Now you can access a view that's only available to logged-in users.

如果你使用的是不同的認(rèn)證后端,這個(gè)方法可能需要不同的憑證。它需要你的后端 ?authenticate()? 方法所需要的任何憑證。
如果憑證被接受且登錄成功,則 ?login()? 返回 ?True?。
最后,在使用這個(gè)方法之前,你需要記得創(chuàng)建用戶賬戶。正如我們上面所解釋的,測(cè)試運(yùn)行器是使用測(cè)試數(shù)據(jù)庫執(zhí)行的,默認(rèn)情況下,數(shù)據(jù)庫中不包含用戶。因此,在生產(chǎn)站點(diǎn)上有效的用戶賬戶在測(cè)試條件下將無法工作。你需要?jiǎng)?chuàng)建用戶作為測(cè)試套件的一部分--無論是手動(dòng)創(chuàng)建(使用 Django 模型 API)還是使用測(cè)試夾具。記住,如果你想讓你的測(cè)試用戶有一個(gè)密碼,你不能直接通過設(shè)置密碼屬性來設(shè)置用戶的密碼——你必須使用 ?set_password()? 函數(shù)來存儲(chǔ)一個(gè)正確的哈希密碼。或者,你可以使用 ?create_user()? 輔助方法來創(chuàng)建一個(gè)具有正確哈希密碼的新用戶。

force_login(user, backend=None)

如果你的網(wǎng)站使用了 Django 的 認(rèn)證系統(tǒng),你可以使用 ?force_login()? 方法來模擬用戶登錄網(wǎng)站的效果。當(dāng)測(cè)試需要用戶登錄,而用戶如何登錄的細(xì)節(jié)并不重要時(shí),可以使用這個(gè)方法代替 ?login()?。
與 ?login()? 不同的是,這個(gè)方法跳過了認(rèn)證和驗(yàn)證步驟:不活躍的用戶(?is_active=False?)被允許登錄,并且不需要提供用戶憑證。
用戶的 ?backend ?屬性將被設(shè)置為 ?backend ?參數(shù)的值(應(yīng)該是一個(gè)點(diǎn)分隔 Python 路徑字符串),如果沒有提供值,則設(shè)置為 ?settings.AUTHENTICATION_BACKENDS[0]??login() ?調(diào)用的 ?authenticate()? 函數(shù)通常會(huì)對(duì)用戶進(jìn)行注釋。
這個(gè)方法比? login()? 快,因?yàn)樗@過了昂貴的密碼散列算法。另外,你也可以通過 在測(cè)試時(shí)使用較弱的哈希算法 來加快 login() 速度。

logout()

如果你的網(wǎng)站使用了 Django 的 認(rèn)證系統(tǒng),?logout()? 方法可以用來模擬用戶注銷網(wǎng)站的效果。
調(diào)用此方法后,測(cè)試客戶端的所有 cookie 和會(huì)話數(shù)據(jù)都會(huì)被清除為默認(rèn)值。隨后的請(qǐng)求將看起來來自一個(gè) ?AnonymousUser?。

測(cè)試響應(yīng)

?get() ?和 ?post()? 方法都會(huì)返回一個(gè) ?Response ?對(duì)象,這個(gè) ?Response ?對(duì)象與 Django 視圖返回的 ?HttpResponse ?對(duì)象是 不 一樣的;測(cè)試響應(yīng)對(duì)象有一些額外的數(shù)據(jù),對(duì)測(cè)試代碼驗(yàn)證很有用。
具體來說,?Response ?對(duì)象具有以下屬性:

class Response

?client?:用于發(fā)出請(qǐng)求并得到響應(yīng)的測(cè)試客戶端。
?content?:以字節(jié)字符串形式的響應(yīng)主體。 這是視圖或任何錯(cuò)誤消息所呈現(xiàn)的最終頁面內(nèi)容。
?context?:模板 ?Context ?實(shí)例,用于渲染產(chǎn)生響應(yīng)內(nèi)容的模板。如果渲染的頁面使用了多個(gè)模板,那么 ?context ?將是一個(gè)按渲染順序排列的 ?Context ?對(duì)象列表。無論在渲染過程中使用了多少模板,你都可以使用 ?[]? 操作符來檢索上下文值。例如,上下文變量 ?name ?可以使用:

>>> response = client.get('/foo/')
>>> response.context['name']
'Arthur'

?exc_info?:一個(gè)由三個(gè)值組成的元組,它提供了關(guān)于在視圖期間發(fā)生的未處理異常(如果有)的信息。值是(type,value,traceback),與 Python 的 ?sys.exc_info()? 返回的值相同。它們的含義是:

  • ?type?:異常的類型。
  • ?value?:異常的實(shí)例。
  • ?traceback?:一個(gè)追溯對(duì)象,在最初發(fā)生異常的地方封裝了調(diào)用堆棧。

如果沒有發(fā)生異常,那么 ?exc_info ?將是 ?None?。

?json(**kwargs)?:解析為 JSON 的響應(yīng)主體。額外的關(guān)鍵字參數(shù)傳遞給? json.loads()?。例如:

>>> response = client.get('/foo/')
>>> response.json()['name']
'Arthur'

如果 ?Content-Type? 頭不是 ?application/json?,那么在試圖解析響應(yīng)時(shí)將會(huì)出現(xiàn)一個(gè) ?ValueError?。

?request?:激發(fā)響應(yīng)的請(qǐng)求數(shù)據(jù)。
?wsgi_request?:由生成響應(yīng)的測(cè)試處理程序生成的 ?WSGIRequest ?實(shí)例。
?status_code?:整數(shù)形式的響應(yīng) HTTP 狀態(tài)。
?templates?:用于渲染最終內(nèi)容的 ?Template ?實(shí)例列表,按渲染順序排列。對(duì)于列表中的每個(gè)模板,如果模板是從文件中加載的,則使用 ?template.name? 獲得模板的文件名。(名字是一個(gè)字符串,如 ?admin/index.html?。)

?resolver_match?:響應(yīng)的 ?ResolverMatch ?的實(shí)例。你可以使用 ?func ?屬性,例如,驗(yàn)證服務(wù)于響應(yīng)的視圖:

# my_view here is a function based view
self.assertEqual(response.resolver_match.func, my_view)

# class-based views need to be compared by name, as the functions
# generated by as_view() won't be equal
self.assertEqual(response.resolver_match.func.__name__, MyView.as_view().__name__)

如果找不到給定的 URL,訪問這個(gè)屬性會(huì)引發(fā)一個(gè) ?Resolver404 ?異常。

和普通的響應(yīng)一樣,你也可以通過 ?HttpResponse.headers? 訪問頭信息。例如,你可以使用 ?response.headers['Content-Type']? 來確定一個(gè)響應(yīng)的內(nèi)容類型。

例外

如果你把測(cè)試客戶端指向一個(gè)會(huì)引發(fā)異常的視圖,并且 ?Client.raise_request_exception? 是 ?True?,那么這個(gè)異常將在測(cè)試用例中可見。然后你可以使用標(biāo)準(zhǔn)的 ?try ... except? 塊或 ?assertRaises()? 來測(cè)試異常。
測(cè)試客戶端看不到的異常只有 ?Http404?、?PermissionDenied?、?SystemExit ?和 ?SuspiciousOperation?。Django 在內(nèi)部捕獲這些異常,并將其轉(zhuǎn)換為相應(yīng)的 HTTP 響應(yīng)代碼。在這些情況下,你可以在測(cè)試中檢查 ?response.status_code?。
如果 ?Client.raise_request_exception? 為 ?False?,測(cè)試客戶端將返回一個(gè) 500 的響應(yīng),就像返回給瀏覽器一樣。響應(yīng)有屬性 ?exc_info ?來提供關(guān)于未處理的異常的信息。

持久狀態(tài)

測(cè)試客戶端是有狀態(tài)的。如果一個(gè)響應(yīng)返回一個(gè) cookie,那么這個(gè) cookie 將被存儲(chǔ)在測(cè)試客戶端,并與所有后續(xù)的 ?get()? 和 ?post()? 請(qǐng)求一起發(fā)送。
不遵循這些 cookie 的過期策略。如果你希望 cookie 過期,請(qǐng)手動(dòng)刪除它或創(chuàng)建一個(gè)新的 Client 實(shí)例(這將有效地刪除所有 cookie)。
測(cè)試客戶端有兩個(gè)屬性,存儲(chǔ)持久化的狀態(tài)信息。你可以作為測(cè)試條件的一部分來訪問這些屬性。

?Client.cookies?:一個(gè) Python ?SimpleCookie ?對(duì)象,包含所有客戶端 cookie 的當(dāng)前值。
?Client.session?:一個(gè)類似字典的對(duì)象,包含會(huì)話信息。要修改會(huì)話然后保存,必須先將其存儲(chǔ)在一個(gè)變量中(因?yàn)槊看卧L問該屬性時(shí)都會(huì)創(chuàng)建一個(gè)新的 ?SessionStore?):

def test_something(self):
    session = self.client.session
    session['somekey'] = 'test'
    session.save()

設(shè)置語言

在測(cè)試支持國(guó)際化和本地化的應(yīng)用程序時(shí),你可能想為測(cè)試客戶端請(qǐng)求設(shè)置語言。這樣做的方法取決于 ?LocaleMiddleware ?是否啟用。
如果啟用了中間件,可以通過創(chuàng)建一個(gè)名為 ?LANGUAGE_COOKIE_NAME ?的 cookie 來設(shè)置語言,其值為語言代碼:

from django.conf import settings

def test_language_using_cookie(self):
    self.client.cookies.load({settings.LANGUAGE_COOKIE_NAME: 'fr'})
    response = self.client.get('/')
    self.assertEqual(response.content, b"Bienvenue sur mon site.")

或在請(qǐng)求中加入 ?Accept-Language? HTTP 頭:

def test_language_using_header(self):
    response = self.client.get('/', HTTP_ACCEPT_LANGUAGE='fr')
    self.assertEqual(response.content, b"Bienvenue sur mon site.")

如果中間件沒有啟用,可以使用 ?translation.override()? 設(shè)置活動(dòng)語言:

from django.utils import translation

def test_language_using_override(self):
    with translation.override('fr'):
        response = self.client.get('/')
    self.assertEqual(response.content, b"Bienvenue sur mon site.")

以下是使用測(cè)試客戶端進(jìn)行的單元測(cè)試:

import unittest
from django.test 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)


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)