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实现从url中提取域名的几种方法
Sep 26 Python
python抓取并保存html页面时乱码问题的解决方法
Jul 01 Python
详解django三种文件下载方式
Apr 06 Python
Python机器学习库scikit-learn安装与基本使用教程
Jun 25 Python
python ChainMap的使用和说明详解
Jun 11 Python
PyQt5 窗口切换与自定义对话框的实例
Jun 20 Python
Django认证系统实现的web页面实现代码
Aug 12 Python
python next()和iter()函数原理解析
Feb 07 Python
Ubuntu中配置TensorFlow使用环境的方法
Apr 21 Python
Pycharm打开已有项目配置python环境的方法
Jul 03 Python
Python必须了解的35个关键词
Jul 16 Python
10张动图学会python循环与递归问题
Feb 06 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
Look And Say 序列php实现代码
2011/05/22 PHP
Php图像处理类代码分享
2012/01/19 PHP
通过PHP current函数获取未知字符键名数组第一个元素的值
2013/06/24 PHP
PHP中substr()与explode()函数用法分析
2014/11/24 PHP
详解PHP中的状态模式编程
2015/08/11 PHP
php使用parse_str实现查询字符串解析到变量中的方法
2017/02/17 PHP
PHP实现的服务器一致性hash分布算法示例
2018/08/09 PHP
用javascript获得地址栏参数的两种方法
2006/11/08 Javascript
JS 密码强度验证(兼容IE,火狐,谷歌)
2010/03/15 Javascript
在多个页面使用同一个HTML片段的代码
2011/03/04 Javascript
JS代码放在head和body中的区别分析
2011/12/01 Javascript
jquery实现多屏多图焦点图切换特效的方法
2015/05/04 Javascript
JavaScript原生编写《飞机大战坦克》游戏完整实例
2017/01/04 Javascript
Three.js 再探 - 写一个微信跳一跳极简版游戏
2018/01/04 Javascript
Vue实现搜索 和新闻列表功能简单范例
2018/03/16 Javascript
图文讲解vue的v-if使用方法
2019/02/11 Javascript
从组件封装看Vue的作用域插槽的实现
2019/02/12 Javascript
Vue动态生成el-checkbox点击无法赋值的解决方法
2019/02/21 Javascript
Nest.js散列与加密实例详解
2021/02/24 Javascript
Python工程师面试题 与Python基础语法相关
2016/01/14 Python
Python的mysql数据库的更新如何实现
2017/07/31 Python
在cmder下安装ipython以及环境的搭建
2018/10/19 Python
Python实现的对本地host127.0.0.1主机进行扫描端口功能示例
2019/02/15 Python
python列表每个元素同增同减和列表元素去空格的实例
2019/07/20 Python
利用python在excel中画图的实现方法
2020/03/17 Python
python 调整图片亮度的示例
2020/12/03 Python
python批量生成身份证号到Excel的两种方法实例
2021/01/14 Python
IE10 Error.stack 让脚本调试更加方便快捷
2013/04/22 HTML / CSS
留学自荐信写作方法
2014/01/27 职场文书
院领导写的就业推荐信
2014/03/09 职场文书
超市开店计划书
2014/04/26 职场文书
新员工考核评语
2014/12/31 职场文书
高校自主招生校长推荐信
2015/03/23 职场文书
使用pycharm运行flask应用程序的详细教程
2021/06/07 Python
redis cluster支持pipeline的实现思路
2021/06/23 Redis
MySQL 原理优化之Group By的优化技巧
2022/08/14 MySQL