Django 中的 csrf_token 与单元测试

《Python Web开发:测试驱动方法》一书中作者使用的 Django 版本是 1.7,而我使用的是1.9.7版(官网已经更新到1.10了)。这就导致书中给出的代码可能有“过时”的部分。

比如,下面是第三章一个单元测试tests.py的代码,运行没有问题。但是当第五章引入表单后,相应模板中需在<form>标签内加入CSRF令牌{% csrf_token %}。此时再次运行此单元测试会报错。

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)

错误信息:

$ 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'...

根据错误信息,是最后一行的断言self.assertEqual(response.content.decode(), expected_html)导致测试失败。

由于AssertionError信息显示不完整,所以将该行断言注释掉,添加2行代码,打印出response.content.decode()expected_html的全部内容。

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

运行测试:

$ 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'...

在渲染模板时,Django 会把这个模板标签替换成一个<input type="hidden">元素,其值是CSRF 令牌。

从上面的html代码可以看出,通过视图函数home_page()渲染得到的响应包含csrf转换的<input>元素,而render_to_string()则未生成该部分,所以导致测试失败。

以 “django csrf_token 测试”为关键字google下,发现已经有人碰到这个问题。可惜代码不全,网页中提到的参考链接已经失效。

再以失效链接中的“django-csrf_token-when-using-render_to_string”为关键词google,stackoverflow上有人给出一个简单的解决方法,在tests.py中的render_to_string()函数内中加一个参数

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

运行测试,不再报错,问题解决。

$ python3 manage.py test lists

Creating test database for alias 'default'...

..

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

Ran 2 tests in 0.012s

OK

Destroying test database for alias 'default'...

Django 中的 csrf_token 与单元测试的更多相关文章

  1. django中写form表单时csrf_token的作用

    之前在学习django的时候,在template中写form时,出现错误.百度,google后要加{% csrf_token %}才可以,之前一直也没研究,只是知道要加个这个东西,具体是什么也不明白. ...

  2. Python单元测试简介及Django中的单元测试

    Python单元测试简介及Django中的单元测试 单元测试负责对最小的软件设计单元(模块)进行验证,unittest是Python自带的单元测试框架. 单元测试与功能测试都是日常开发中必不可少的部分 ...

  3. django中csrf_token处理方式

    第一:先在HTML中加入{% csrf_token %} $.ajax({ url: '{% url "ceshi:list" %}', type: 'post', dataTyp ...

  4. django中tinymce添加图片上传功能

    主要参考以下: https://pixabay.com/en/blog/posts/direct-image-uploads-in-tinymce-4-42/ http://blog.csdn.net ...

  5. Django中csrf错误

    CSRF(Cross-site request forgery)跨站请求伪造,也被称为“one click attack”或者session riding,通常缩写为CSRF或者XSRF,是一种对网站 ...

  6. Django中的CSRF

    CSRF(Cross Site Request Forgery, 跨站域请求伪造) CSRF 背景与介绍 CSRF(Cross Site Request Forgery, 跨站域请求伪造)是一种网络的 ...

  7. Django中使用ModelForm实现Admin功能

    接上一篇<Django中使用Bootstrap> ModelForm 可以将数据库中的信息展示在一个表中,因此我们在查询数据库信息时可以使用ModelForm在前端展示查询到的信息. 在上 ...

  8. Django中的Form表单

    Django中已经定义好了form类,可以很容易的使用Django生成一个表单. 一.利用Django生成一个表单: 1.在应用下创建一个forms文件,用于存放form表单.然后在forms中实例华 ...

  9. Django中的ORM

    Django中ORM的使用. 一.安装python连接mysql的模块:MySQL-python sudo pip install MySQL-python 安装完成后在python-shell中测试 ...

随机推荐

  1. win10家庭版转专业版并激活

    之前重装win10的时候没注意,不小心装成家庭版. 本以为家庭版也没什么,后来发现这对程序员来说造成致命打击. 在系统信息页面底部点击“更改密匙”,输入win10升级产品密匙:VK7JG-NPHTM- ...

  2. UVA489 - Hangman Judge【紫书例题4.2】

    题意:就是给出一个字符串,让你去一个一个猜测,相同字母算一次,如果是之前猜过的也算错,如果你在错7次前猜对就算你赢,文章中是LRJ的例题代码. #include<stdio.h> #inc ...

  3. 【codeforces 483B】Friends and Presents

    [链接] 我是链接,点我呀:) [题意] [题解] 我们可以二分n的值,设为mid 那么对于n=mid 我们可以算出来以下3个东西 temp1 = n/x; temp2 = n/y; temp3 = ...

  4. mybatis源码阅读-Transaction和TransactionFactory(四)

    Transaction 类图 接口定义 public interface Transaction { Connection getConnection() throws SQLException; v ...

  5. [bzoj3530][Sdoi2014]数数_AC自动机_数位dp

    数数 bzoj-3530 Sdoi-2014 题目大意:给你一个整数集合,求所有不超过n的正整数,是的它的十进制表示下不能再一段等于集合中的任意数. 注释:$1\le n \le 1200$,$1\l ...

  6. hdu - 3498 - whosyourdaddy(反复覆盖DLX)

    题意:N(2 ≤ N ≤ 55)个点,M(0 ≤ M ≤ N*N)条无向边,删除一个点会把与其相邻的点一起删掉.问最少删几次能够删掉全部点. 题目链接:pid=3498">http:/ ...

  7. C++:探究纯虚析构函数以及实现数组的高速排序与链表的归并排序

    C++:探究纯虚析构函数以及实现数组的高速排序与链表的归并排序 标签: 数据结构 数组 链表 高速排序 归并排序 抽象类 虚继承 by 小威威 1.介绍 本篇博文将通过课后作业的(15 C++ Hom ...

  8. Jquery-Uncaught ReferenceError: $ is not defined报错

    在我的jsp页面上有这些js代码: //载入数据 $(document).ready(function() { var param={}; param.page=3; param.size=10; $ ...

  9. NEU操作系统实验课4——线程同步

    实验要求: 创建两个线程按数字顺序打印10以下自然数,其中一个线程打印1-3及8-10:另一个线程打印4-6.要求使用线程同步机制实现上述打印顺序. 看网上的资料学习了两种写法 C++11的,使用了s ...

  10. Laravel-查询作用域

    Laravel-查询作用域 标签(空格分隔): php, laravel 全局作用域 ## 编写全局作用域 ## 编写全局作用域很简单.定义一个实现 Illuminate\Database\Eloqu ...