Django单元测试工具test client使用详解


Posted in Python onAugust 02, 2019

The test client
test client是一个python类,来模拟一个简单的“哑”浏览器,允许你来测试你的view函数.你可以使用test client完成下列事情:

1.模拟"Get"和"Post"请求,观察响应结果--从HTTP(headers,status codes)到页面内容.
2.检查重定向链(如果有的话),在每一步检查URL和status code。
3.用一个包括特定值的模板context来测试一个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的实例来使用test client。

注意:请求网页时,使用path而不是整个domain。

>>> c.get('/login/')

是正确的。

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

是错误的。

test client不适合操作不是由Django建立的网站.所以,请求其它网页时,请使用python的标准库--urllib或者urllib2.

为了解析URl,test client使用由ROOT_URLCONF(settings.py)指定的URLconf。

默认情况下,test client会忽略CSRF检查,如果要强制进行CSRF检查,可以

csrf_client = Client(enforce_csrf_checks=True)

Making Requests

使用django.test.client.Client()来执行请求。

class Client(enforce_csrf_checks=False, **defaults)

可以使用关键字参数来指定默认的请求报头:

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

记得在USER_AGENT前加HTTP_。

Client实例具有以下方法:

get(path, data={}, follow=False, **extra)

执行一个GET请求并返回Response对象。

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

相当于向以下url执行GET:

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

extra关键字参数可用作请求报头:

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

当然也可以将查询字符对编码后加入url:

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

data参数的优先级在编码后的url之上。

如果将follow设置为True,client会追踪任何重定向,返回的response有redirect_chain属性,包括所有重定向过程中的url和状态码组成的元祖列表。

如果有个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)

执行一个POST请求并返回response对象,data参数为POST数据。

如果提供content_type参数(例如 text/xml),数据会被作为报头中Content-Type的类型进行POST上传。

如果不提供content_type参数,数据会被作为multipart/form-data类型上传。

为一个参数提交多个多个值时--比如选住<select multiple>域的多个值--这些值可以是列表或者元组.举例来说,提交choice域的三个被选中的值:

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

上传文件:

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

文件的名字'attachment'是不相关的,取决于你处理文件的代码。

如果同一个文件要post多次,注意每次post都要恢复文件的指针,最简单的方法就是将文件关闭再重新打开。

注意文件要以正确的方式被打开以便于读取,如果文件是binary data,例如读取img时,要将打开模式设为rb。

post的路径中也可以包含查询字符对:

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

这样既会通过post上传data数据,也向GET确定visitor=True。

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

做OPTIONS请求,对测试REST接口很有用。data被用作请求的主体。

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

做PUT请求,测试RESTful接口。

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

做PATCH请求,测试RESTful接口。

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

做DELETE请求,测试RESTful接口。

login(**credentials)

如果使用django的用户验证系统,可用login方法进行测试。

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

登陆成功的话,返回True。

使用之前,当然要创建一个用户。由于测试数据库使用的是单独的数据库,原先数据库中的用户是不能用于测试的。

设置密码时,不能用user的密码属性进行设置,而是用set_password()方法设置正确的哈希密码,或者使用create_user()方法创建一个带哈希密码的用户。

logout()

登出。

Testing Responses

client的get和post方法都返回response对象,和HttpResponse对象是不同的。

class Response具有以下属性:

client:the test client

content:response的主体,string类型,是view render后的页面的最终内容,或者是错误信息。

context:用来渲染模板的context实例。如果页面使用了多个模板,那context就会是Context Object列表.它们的排序方式就是它们被渲染的顺序。

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

request:用于请求的数据。

status_code:状态码。

templates:被用来渲染最终的content的Template实例列表.template.name可以得到template的文件名,如果template是由文件载入的话(如 'admin/index.html')。那template就会是Template列表,它们的排序方式就是它们被渲染的顺序.

response也可以当做字典来查询Http header:

response['Content-Type']

Exceptions

如果你将TestClient指向了由view函数raise的异常,那这个异常在test case里是可见的.你可以使用标准的try...except块或者assertRaises()来测试它们.对test client唯一不可见的异常是Http404,PermissionDenied和SystemExit。django会在内部捕捉这些异常并返回合适的response.这种情况下,你可以查看下你的response.status_code.

Persistent state

如果一个response返回了一个cookie,那么这个cookie就会被存储在test client里,并被其后的所有get()和post()传送.如果你想要终止这个cookie,你可以新建一个Client实例,或者手动删除它。

一个test client具有两个存储持久化状态信息的属性:

Client.cookies

一个python SimpleCookie对象,存储cilent的所有cookie。

Client.sessions

包含session信息的类字典对象。

如果要修改一个session并且存储,首先将session存储在变量中:

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

一个使用client进行测试的实例:

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的一些功能

默认的test client

每个django.test.*TestCase的test case实例都会访问django test client,所以Client可以不用实例化,而直接用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

如果数据库里没有数据,那么对于一个基于数据库的网站来说,test case并无多大的用处.为了给测试数据库加入测试数据更方便,django提供了载入fixtures的方法.

fixture是一系列的数据集合,django知道如何将它导入数据库。

创建fixture最直接的方法就是使用manage.py dumpdata.当然,这假设你的实际数据库里已经有数据了.

注意:

如果你运行过manage.py syncdb命令,那么你已经使用过fixture了--只是你不知道而已。当你使用syncdb去创建数据库时,会创建一个叫initial_data的fixture。

其他名字的Fixture可以通过manage.py loaddata命令手动安装.

一旦建立了一个fixture,并将它放在了某个django app的fixtures目录中,你就可以在你的测试类里使用它了:

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()

这是具体发生的过程:

1. 在setup()运行前,django会清空数据库,相当于你执行了syncdb。

2.然后,所有的fixture会被安装.在例子中,django会安装任何一个名字为mammals的JSON格式的fixture和名为birds的fixture数据。

Assertions

除了python中的assertEqual()和assertTrue()外,django的TestCase还提供了几个额外的assert方法。

assertContains(response, text, count=None, status_code=200, msg_prefix='', html=False)

断言response是否与status_code和text内容相应。将html设为True会将text作为html处理。

assertJSONEqual(raw, expected_data, msg=None)

断言Json片段raw和expected_data是否相当。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python比较2个xml内容的方法
May 11 Python
Python简单网络编程示例【客户端与服务端】
May 26 Python
Python浅复制中对象生存周期实例分析
Apr 02 Python
详谈Numpy中数组重塑、合并与拆分方法
Apr 17 Python
python lxml中etree的简单应用
May 10 Python
python SocketServer源码深入解读
Sep 17 Python
500行代码使用python写个微信小游戏飞机大战游戏
Oct 16 Python
django使用xadmin的全局配置详解
Nov 15 Python
Python随机数函数代码实例解析
Feb 09 Python
Python Tornado之跨域请求与Options请求方式
Mar 28 Python
PyCharm MySQL可视化Database配置过程图解
Jun 09 Python
Python使用MapReduce进行简单的销售统计
Apr 22 Python
Django使用unittest模块进行单元测试过程解析
Aug 02 #Python
pip安装python库的方法总结
Aug 02 #Python
python twilio模块实现发送手机短信功能
Aug 02 #Python
python代码 FTP备份交换机配置脚本实例解析
Aug 01 #Python
Windows系统Python直接调用C++ DLL的方法
Aug 01 #Python
Python CVXOPT模块安装及使用解析
Aug 01 #Python
Python Selenium 之数据驱动测试的实现
Aug 01 #Python
You might like
解决phpmyadmin中缺少mysqli扩展问题的方法
2013/05/06 PHP
Discuz7.2版的faq.php SQL注入漏洞分析
2014/08/06 PHP
php中instanceof 与 is_a()区别分析
2015/03/03 PHP
php四种定界符详解
2017/02/16 PHP
微信公众号开发之通过接口删除菜单
2017/02/20 PHP
老生常谈php 正则中的i,m,s,x,e分别表示什么
2017/03/02 PHP
Javascript实现的鼠标经过时播放声音
2010/05/18 Javascript
收集的10个免费的jQuery相册
2011/02/26 Javascript
JavaScript 更严格的相等 [译]
2012/09/20 Javascript
JavaScript高级程序设计(第3版)学习笔记5 js语句
2012/10/11 Javascript
jQuery多项选项卡的实现思路附样式及代码
2014/06/03 Javascript
javascript实现PC网页里的拖拽效果
2016/03/14 Javascript
RequireJS使用注意细节
2016/05/15 Javascript
Centos7 中 Node.js安装简单方法
2016/11/02 Javascript
AngularJS ui-router (嵌套路由)实例
2017/03/10 Javascript
详解nodejs微信公众号开发——5.素材管理接口
2017/04/11 NodeJs
vue.js指令v-for使用以及下标索引的获取
2019/01/31 Javascript
微信小程序实现手势滑动效果
2019/08/26 Javascript
Vue 使用iframe引用html页面实现vue和html页面方法的调用操作
2020/11/16 Javascript
[59:42]Secret vs Alliacne 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/17 DOTA
Python实现网站文件的全备份和差异备份
2014/11/30 Python
使用httplib模块来制作Python下HTTP客户端的方法
2015/06/19 Python
python中requests和https使用简单示例
2018/01/18 Python
Python实现针对给定单链表删除指定节点的方法
2018/04/12 Python
Python操作Oracle数据库的简单方法和封装类实例
2018/05/07 Python
python将txt文件读取为字典的示例
2018/12/22 Python
解决python super()调用多重继承函数的问题
2019/06/26 Python
python中的split()函数和os.path.split()函数使用详解
2019/12/21 Python
pytorch nn.Conv2d()中的padding以及输出大小方式
2020/01/10 Python
Python函数必须先定义,后调用说明(函数调用函数例外)
2020/06/02 Python
python rolling regression. 使用 Python 实现滚动回归操作
2020/06/08 Python
2021年的Python 时间轴和即将推出的功能详解
2020/07/27 Python
思想汇报范文
2013/11/04 职场文书
毕业生的自我评价范文
2013/12/31 职场文书
作风建设演讲稿
2014/05/23 职场文书
Mysql 如何实现多张无关联表查询数据并分页
2021/06/05 MySQL