在《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'...