Django 中的 csrf_token 與單元測(cè)試

《Python Web開(kāi)發(fā):測(cè)試驅(qū)動(dòng)方法》一書(shū)中作者使用的 Django 版本是 1.7,而我使用的是1.9.7版(官網(wǎng)已經(jīng)更新到1.10了)。這就導(dǎo)致書(shū)中給出的代碼可能有“過(guò)時(shí)”的部分。

比如,下面是第三章一個(gè)單元測(cè)試tests.py的代碼,運(yùn)行沒(méi)有問(wèn)題。但是當(dāng)?shù)谖逭乱氡韱魏螅鄳?yīng)模板中需在<form>標(biāo)簽內(nèi)加入CSRF令牌{% csrf_token %}。此時(shí)再次運(yùn)行此單元測(cè)試會(huì)報(bào)錯(cuò)。

from django.test import TestCase
from django.core.urlresolvers import resolve
from django.http import HttpRequest
from django.template.loader import render_to_string

from .views import home_page


class HomePageTest(TestCase):

    def test_root_url_resolves_to_home_page_view(self):
        found = resolve('/')
        self.assertEqual(found.func, home_page)

    def test_home_page_returns_correct_html(self):
        request = HttpRequest()
        response = home_page(request)
        expected_html = render_to_string('home.html')
        self.assertEqual(response.content.decode(), expected_html)

錯(cuò)誤信息:

$ python3 manage.py test lists

Creating test database for alias 'default'...

F.

======================================================================

FAIL: test_home_page_returns_correct_html (lists.tests.HomePageTest)

----------------------------------------------------------------------

Traceback (most recent call last):

  File "/home/panzeyan/PycharmProjects/TDD/superlists/lists/tests.py", line 20, in test_home_page_returns_correct_html

    self.assertEqual(response.content.decode(), expected_html)

AssertionError: '<htm[240 chars]     <input type=\'hidden\' name=\'csrfmiddlew[184 chars]l>\n' != '<htm[240 chars]     \n        </form>\n\n        <table id="i[87 chars]l>\n'



----------------------------------------------------------------------

Ran 2 tests in 0.256s



FAILED (failures=1)

Destroying test database for alias 'default'...

根據(jù)錯(cuò)誤信息,是最后一行的斷言self.assertEqual(response.content.decode(), expected_html)導(dǎo)致測(cè)試失敗。

由于AssertionError信息顯示不完整,所以將該行斷言注釋掉,添加2行代碼,打印出response.content.decode()expected_html的全部?jī)?nèi)容。

print('response.content.decode()\n', response.content.decode())
print('expected_html\n', expected_html)

運(yùn)行測(cè)試:

$ python3 manage.py test lists
Creating test database for alias 'default'...
response.content.decode()
 <html>
    <head>
        <title>To-Do lists</title>
    </head>
    <body>
        <h1>Your To-Do list</h1>

        <form method="post">
            <input name="item_text" id="id_new_item" placeholder="Enter a to-do item" />
            <input type='hidden' name='csrfmiddlewaretoken' value='tl2rZy1RBSLY75DD2ysZ4KHF0DePGWQs' />
        </form>

        <table id="id_list_table">
            <tr><td>1: </td></tr>
        </table>
    </body>
</html>

expected_html
 <html>
    <head>
        <title>To-Do lists</title>
    </head>
    <body>
        <h1>Your To-Do list</h1>

        <form method="post">
            <input name="item_text" id="id_new_item" placeholder="Enter a to-do item" />
            
        </form>

        <table id="id_list_table">
            <tr><td>1: </td></tr>
        </table>
    </body>
</html>

..
----------------------------------------------------------------------
Ran 2 tests in 0.015s

OK
Destroying test database for alias 'default'...

在渲染模板時(shí),Django 會(huì)把這個(gè)模板標(biāo)簽替換成一個(gè)<input type="hidden">元素,其值是CSRF 令牌。
從上面的html代碼可以看出,通過(guò)視圖函數(shù)home_page()渲染得到的響應(yīng)包含csrf轉(zhuǎn)換的<input>元素,而render_to_string()則未生成該部分,所以導(dǎo)致測(cè)試失敗。

以 “django csrf_token 測(cè)試”為關(guān)鍵字google下,發(fā)現(xiàn)已經(jīng)有人碰到這個(gè)問(wèn)題??上Тa不全,網(wǎng)頁(yè)中提到的參考鏈接已經(jīng)失效。

再以失效鏈接中的“django-csrf_token-when-using-render_to_string”為關(guān)鍵詞google,stackoverflow上有人給出一個(gè)簡(jiǎn)單的解決方法,在tests.py中的render_to_string()函數(shù)內(nèi)中加一個(gè)參數(shù)

expected_html = render_to_string('home.html', request=request)

運(yùn)行測(cè)試,不再報(bào)錯(cuò),問(wèn)題解決。

$ python3 manage.py test lists

Creating test database for alias 'default'...

..

----------------------------------------------------------------------

Ran 2 tests in 0.012s



OK

Destroying test database for alias 'default'...
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1、前言##### 最近在學(xué)習(xí)django,使用的書(shū)是《Python Web開(kāi)發(fā) 測(cè)試驅(qū)動(dòng)方法》,在第四章中遇到了...
    嘿嘿_小于同學(xué)閱讀 780評(píng)論 0 1
  • 22年12月更新:個(gè)人網(wǎng)站關(guān)停,如果仍舊對(duì)舊教程有興趣參考 Github 的markdown內(nèi)容[https://...
    tangyefei閱讀 35,418評(píng)論 22 257
  • 此段內(nèi)容簡(jiǎn)要來(lái)自自強(qiáng)學(xué)堂的教程詳情請(qǐng)查詢自強(qiáng)學(xué)堂 一、 后臺(tái)的運(yùn)作流程 接收request請(qǐng)求 處理數(shù)據(jù) 獲取請(qǐng)求...
    coder_ben閱讀 5,349評(píng)論 6 56
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,628評(píng)論 19 139
  • (一)、啟動(dòng)服務(wù)器 (二)、創(chuàng)建數(shù)據(jù)庫(kù)表 或 更改數(shù)據(jù)庫(kù)表或字段 Django 1.7.1及以上 用以下命令 1....
    夏天夏星閱讀 5,968評(píng)論 0 17

友情鏈接更多精彩內(nèi)容