django测试(二)
test client运行机制test client并不需要有Web server.这是因为test client避开了HTTP的额外开销,直接处理Django框架.这样就可以是unit test运行飞快.
当请求页面时需要指定url路径.不是整个域路径.
这是对的
>>> c.get('/login/')
这是错的
>>> c.get('http://www.example.com/login/')
test client不适合操作不是由Django建立的网站.如果,你非要如此,请使用python的标准库--urllib或者urllib2.
为了解析URl,test client使用由ROOT_URLCONF(settings.py)指定的URLconf
尽管上例可以在python内置环境里运行,一些test client的功能,尤其是模板相关的功能,只有在test运行时才可以使用.
Making requests
可以使用django.test.client.Client类来构造request.它在构造时并不需要参数.
>>> c = Client()
一个client实例可以调用下列方法:
get(path, data={}):
创建一个path的Get请求,并返回Response object.
Data字典的key-value值会被用来创建一个由Get得到的数据.如:
c = Client()
c.get('/customers/details/', {'name':'fred', 'age':7})
它与下述请求等价:
[url]http://yoursite.com/customers/details/?name=fred&age=7[/url]
post(path, data={}, content_type=MULTIPART_CONTENT)
创建一个path的POST请求,并返回Response object.
Data字典的key-value值会被用来创建POST的数据.如:
>>> c = Client()
>>> c.post('/login/', {'name': 'fred', 'passwd': 'secret'})
它会请求'/login/'这个url,并发送数据name=fred&passwd=secret
如果提供了content_type参数,data会被包含在POST请求里,以HTTP头Content-Type格式被发送.
如果没有提供,data会以multipart/form-data的content_type格式被发送.这样的话,Data字典的key-value值会作为multipart message进行编码,并创建一个post数据载体.
为一个参数提交多个多个值时--比如选住<select multiple>域的多个值--这些值可以是列表或者元组.举例来说,提交choice域的三个被选中的值:
{'choices': ('a', 'b', 'd')}
提交文件是一个特殊情况.你需要提供你想要上传的文件的文件名和操作这个文件的File变量:
>>> c = Client()
>>> f = open('wishlist.doc')
>>> c.post('/customers/wishes/', {'name': 'fred', 'attachment': f})
>>> f.close()
注意:在你使用这个file后需要手动关闭它.
login(**credentials)
如果你的网站使用了django的验证系统,你可以使用test client的login()方法去登录用户.
在你调用这个方法后,test client就会拥有登录用户所有的cookies 和 session.
credentials参数的格式取决于你是用的验证程序(authentication backend,有setting里的AUTHENTICATION_BACKENDS定义).如果你使用的是django默认提供的验证程序就应该是用户名和密码.
>>> c = Client()
>>> c.login(username='fred', password='secret')
>>> # Now you can access a view that's only available to logged-in users.
如果你使用了不同的验证程序,login就需要不同的credentials参数,它需要的值由你定义的authenticate()决定.
如果credentials通过验证,login()返回True,并登录成功.
最后,记住在使用login()方法前,你需要创建一个账户,因为我们创建的测试数据库默认是没有任何数据的.你可以使用Django model api去创建一个用户账号,或者使用test fixture.
logout()
如果你的网站使用了django的验证系统,你可以使用test client的logout()方法注销用户.
在你调用这个方法后,test client就会清理所有的cookie和session数据.
测试responses
get()和post()方法返回的都是Response object.这个Response object不同于view函数返回的HttpResponse.这个test Response object包含了更多的需要测试验证的数据.
具体说,一个Response拥有下列的属性.
属性 解释
client 被用来生成request的TestClient
content response的主体,string类型,是view render后的页面的最终内容,或者是错误信息.
context 用来渲染模板的template Context.如果页面使用了多个模板,那context就会是Context Object列表.它们的排序方式就是它们被渲染的顺序.
headers response的HTTP头,dict类型.
request 作用于response的request数据
status_code response的状态码,integer数据.
template 被用来渲染最终的content的Template实例.template.name可以得到template的文件名,如果template是由文件载入的话(如 'admin/index.html').如果页面使用了多个模板,
那template就会是Template列表,它们的排序方式就是它们被渲染的顺序.
Exceptions
如果你将TestClient指向了由view函数raise的异常,那这个异常在test case里是可见的.你可以使用标准的try...catch块或者unittest.TestCase.assertRaises()来测试它们.
对testclient唯一不可见的异常是Http404,PermissionDenied和SystemExit.django会在内部捕捉这些异常并返回合适的response.这种情况下,你可以查看下你的response.status_code.
Persistent state
如果一个response返回了一个cookie,那么这个cookie就会被存储在test client里,并被其后的所有get()和post()传送.如果你想要终止这个cookie,你可以新建一个Client实例,或者手动删除它.(删除更有效)
cookies python SimpleCookie object,包含了所有client cookies的当前值.
session 一个类似于dict的object,包含了sesion信息
例子
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 respose is 200 OK.
self.failUnlessEqual(response.status_code, 200)
# Check that the rendered context contains 5 customers.
self.failUnlessEqual(len(response.context['customers']), 5)
TestCase
一般的python单元测试类要继承unittest.TestCase.django提供了一个子类--django.test.TestCase,提供了一些测试网站更有用的功能.
将一个普通的unittest.TestCase转换为django TestCase非常容易:仅仅需要将base class 由unittest.TestCase换成django.test.TestCase.所有的标准python单元测试会继续工作.
默认的 test client
每一个test case都可以都可以访问test client.你也可以通过self.client访问它.
这就意为着你不用在每个test方法中都实例化Client.
import unittest
from django.test.client import Client
class SimpleTest(unittest.TestCase):
def test_details(self):
client = Client()
response = client.get('/customer/details/')
self.failUnlessEqual(response.status_code, 200)
def test_index(self):
client = Client()
response = client.get('/customer/index/')
self.failUnlessEqual(response.status_code, 200)
用self.client来替换,就是
from django.test import TestCase
class SimpleTest(TestCase):
def test_details(self):
response = self.client.get('/customer/details/')
self.failUnlessEqual(response.status_code, 200)
def test_index(self):
response = self.client.get('/customer/index/')
self.failUnlessEqual(response.status_code, 200)
Fixture loading
如果数据库里没有数据,那么对于一个基于数据库的网站来说,test case并无多大的用处.为了给测试数据库加入测试数据更方便,django提供了载入fixtures的方法.
fixture是一系列的数据,django知道如何将它导入数据库.
创建fixture最直接的方法就是使用manage.py dumpdata.当然,这假设你的实际数据库里已经有数据了.
注意:
如果你运行过manage.py syncdb命令,那么你已经使用过fixture了--只是你不知道而已:)当你使用syncdb去创建数据库时,Fixture--initial_data.
其他名字的Fixture可以通过manage.py loaddata命令手动安装.
一旦建立了一个fixture,并将它放在了django project文件内,你就可以在你的测试类里使用它了.]
from django.test import TestCase
from myapp.models import Animal
class AnimalTestCase(TestCase):
fixtures = ['mammals.json', 'birds']
def setUp(self):
# Test definitions as before.
def testFluffyAnimals(self):
# A test that uses the fixtures.
这是具体发生的过程:
在setup()运行前,django会清空数据库,相当于你执行了syncdb.
然后,所有的fixture会被安装.在例子中,django会安装任何一个名字为mammals的JSON格式的fixture和名为birds的fixture数据.
这种清空/载入行为对test case里的每一个test都会重复执行一次.
Emptying the test outbox 好
页:
[1]