基于Django的程序测试
原文地址:
https://docs.djangoproject.com/en/1.11/topics/testing/
自动化测试是非常有用的,你可以使用测试套件来解决,避免许多问题,例如:
- 当你需要对之前的代码进行修改时,可以复用之前的测试代码,来发现修改代码对应用逻辑的影响;
- 当你写新代码时,可以自动化检验实际允许逻辑是否和你的设计一致;
由于网络应用逻辑比较负责,且涉及到很多方面,例如:http请求路由、表单校验,应用逻辑处理,页面渲染,因此测试网页应用是非常复杂的。Django提供了许多测试工具,这些工具可以:模拟网络请求、插入测试数据、检验应用输出、代码校验。
本文分为如下几个部分:
- 如何使用Django 自身的测试框架进行测试;
- Django提供的测试工具
- Django和其他测试框架进行集成。
1. 如何使用Django自身测试框架
https://docs.djangoproject.com/en/1.11/topics/testing/overview/
Django单元测试使用来Python标准库:unittest。
例子:
from django.test import TestCase
from myapp.models import Animal
class AnimalTestCase(TestCase):
def setUp(self):
Animal.objects.create(name="lion", sound="roar")
Animal.objects.create(name="cat", sound="meow")
def test_animals_can_speak(self):
"""Animals that can speak are correctly identified"""
lion = Animal.objects.get(name="lion")
cat = Animal.objects.get(name="cat")
self.assertEqual(lion.speak(), 'The lion says "roar"')
self.assertEqual(cat.speak(), 'The cat says "meow"')
在测试时,默认是寻找所有的nittest.TestCase的子类,然后构造相关的测试用例进行测试。
1.1 测试用例运行顺序
Django运行测试用例的顺序为:
- 所有TestCase的子类先运行;
- 基于Django定义的测试类(例如SimpleTestCase)的子类;
- 其他unittest.TestCase的子类;
2.Django测试工具
2.1 测试客户端:test client
test client 是一个Python 类,该类描述了一个简单的web 浏览器,你可以使用该类来测试你的视图处理函数view ,测试和你的应用交互逻辑。该类的用法包括:
- 模拟发出GET/POST 请求,并且获取对应的response;
- 观察URL的重定向链。
- 测试请求渲染模版
注意:Django test client 不是 Selenium 或是其他内置浏览器的替代品。
先来一个简单的例子:
>>> from django.test import Client
>>> c = Client()
>>> response = c.post('/login/', {'username': 'john', 'password': 'smith'})
>>> response.status_code
200
>>> response = c.get('/customer/details/')
>>> response.content
b'<!DOCTYPE html...'
注意:运行上述测试用例都不需要Webserver处于运行状态。实际上,上述代码避免了和HTTP 和与Django框架交互的开销。
2.1.1 使用Client
类声明:
class Client(enforce_csrf_checks=False, **defaults)
创建 django.test.Client实例
c = Client(HTTP_USER_AGENT='Mozilla/5.0')
(2)类实例方法:
- get(path, data=None, follow=False, secure=False, **extra):发送Get请求。返回Response对象。
>>> c = Client()
>>> c.get('/customers/details/', {'name': 'fred', 'age': 7})
等同于请求:/customers/details/?name=fred&age=7
extra参数可用定义 http请求header。
当follow为true 时,会跟踪重定向请求。
- post(path, data=None, content_type=MULTIPART_CONTENT, follow=False, secure=False, **extra):发送post请求
>>> c = Client()
>>> c.post('/login/', {'name': 'fred', 'passwd': 'secret'})
data中指定post数据;另外,要提交file数据,需要指定文件指针,例如:
>>> c = Client()
>>> with open('wishlist.doc') as fp:
... c.post('/customers/wishes/', {'name': 'fred', 'attachment': fp})
- head(path, data=None, follow=False, secure=False, **extra): 发送head请求
- options(path, data=’’, content_type=‘application/octet-stream’, follow=False, secure=False, **extra):
- put(path, data=’’, content_type=‘application/octet-stream’, follow=False, secure=False, **extra)
- patch(path, data=’’, content_type=‘application/octet-stream’, follow=False, secure=False, **extra)
- delete(path, data=’’, content_type=‘application/octet-stream’, follow=False, secure=False, **extra)
- trace(path, follow=False, secure=False, **extra)
2.1.2 返回的response的处理
client发送请求后,返回的是一个Response对象(注意,该对象不是一个HttpResponse类实例)。该response对象具有如下属性:
- client :发送绑定的请求的client;
- request: 对应的request对象;
- content: response body
- context:
- status_code
- wsgi_request
- resolver_match
状态的持久化
test client 是有状态的。如果某个response返回了cookie数据,则cookie数据会保存起来,后续的get/post请求会将cookie数据发送出去。
这些cookie数据不会过期。如果你想让某些数据过期,则需要手动的删除,或是创建一个client对象。
这些状态数据存储在:Client.cookies,Client.session 属性中。
2.2 实例:
import unittest
from django.test 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)
2.3 其他特性
2.3.1 Fixture
如果数据库里没有数据,那么对于一个基于数据库的网站来说,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()
这是具体发生的过程:
- 在setup()运行前,django会清空数据库,相当于你执行了syncdb。
2.然后,所有的fixture会被安装.在例子中,django会安装任何一个名字为mammals的JSON格式的fixture和名为birds的fixture数据
2.3.2 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是否相当。
3. 在Django使用其他测试框架进行测试
3.1 RequestFactory
RequestFacTory 和test client 具有相同的API。test client 是行为表现和浏览器类型,但是RequestFacTory是直接生成一个能被view接受的 request实例。因此,你可以想测试其他函数一样,测试你的应用函数。
相比test client 来说,requestfactory的功能比较受限,具体表现在:
- requestfactory 只能发送 get(), post(), put(), delete(), head(), options(), ,trace()请求。
- 上述方法接受的参数和test client类似,处理follow参数
- 不支持 中间件。session ,认知参数必须由测试用例编写人自己提供(如果需要的话)
使用示例:
from django.contrib.auth.models import AnonymousUser, User
from django.test import TestCase, RequestFactory
from .views import MyView, my_view
class SimpleTest(TestCase):
def setUp(self):
# Every test needs access to the request factory.
self.factory = RequestFactory()
self.user = User.objects.create_user(
username='jacob', email='jacob@…', password='top_secret')
def test_details(self):
# Create an instance of a GET request.
request = self.factory.get('/customer/details')
# Recall that middleware are not supported. You can simulate a
# logged-in user by setting request.user manually.
request.user = self.user
# Or you can simulate an anonymous user by setting request.user to
# an AnonymousUser instance.
request.user = AnonymousUser()
# Test my_view() as if it were deployed at /customer/details
response = my_view(request)
# Use this syntax for class-based views.
response = MyView.as_view()(request)
self.assertEqual(response.status_code, 200)
3.2 使用其他测试框架
虽然Django 没有显示的声明支持除了unit test之外的测试框架,但是Django提供了激活测试用例的方式,这些测试用例运行起来就好像是Django的普通测试用例。
当运行 ./manage.py test
脚本时,Django 寻找TEST_RUNNER
设置,决定运行动作。默认情况下,TEST_RUNNER 指向django.test.runner.DiscoverRunner
。该类指定类Django的默认测试行为,包括:
- 执行全局的 pre-test setup;
- 在当前目录下,寻找 文件名匹配
test*.py
的测试文件; - 创建测试数据库;
- 运行migrate 安装相关model,初始化数据库中的数据;
- 运行测试用例;
- 销毁数据库;
- 执行全局的post-test teardown
- Github 项目推荐 | 用于构建端对端对话系统和训练聊天机器人的开源库 —— DeepPavlov
- 我身边的一些数据库事故 (r5笔记第52天)
- 一个清理脚本的改进思路(r5笔记第51天)
- 【专业技术】Python爬虫:抓取手机APP的传输数据
- 海量数据迁移之传输表空间(一) (r5笔记第71天)
- 一条sql语句的改进探索(r5笔记第70天)
- 【专业技术】Node.js 究竟是什么?
- Github 项目推荐 | 用 Pytorch 实现的 WaveNet-Vocoder
- 重启数据库的一场闹剧(r5笔记第68天)
- 【C语言系列】基础语法案例分析(初级篇)
- 一次ORA-00600问题的排查和分析(r5笔记第64、65天)
- SpringMVC入门就这么简单
- pl/sql中的forall简单测试(r5笔记第63天)
- SpringMVC【开发Controller】详解
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Python 技术篇-连接oracle数据库并执行sql语句实例演示,python连接oracle数据库oci详细配置方法
- MySQL 技术篇-mysql数据库的安装、配置与使用实例演示
- JavaScript 技术篇-js代码获取当前操作系统信息、浏览器版本信息实例演示,windows NT版本对照表
- Oracle 数据库impdp导入数据库版本和dmp数据库文件版本不匹配问题解决方法,ORA-39142版本号不兼容、ORA-39000转储文件说明错误解决方法
- 实践总结:基于Kbone使用React同构开发小程序
- BAT 批处理命令 - 实现输出当前文件夹下的所有文件夹名的功能实例演示
- Python+Selenium 自动化-指定chrome驱动运行selenium实例演示,运行指定位置下的浏览器驱动
- Linux 命令查找指定文件夹下符合查询条件的文件和文件夹实例演示
- 用Python实现一个最新QQ办公版(TIM)的登录界面
- Oracle 数据库直接执行本地sql文件、sql脚本实例演示
- Oracle 数据库利用回收站恢复删除的表实例演示
- Linux 命令利用scp实现从服务器共享地址上传下载文件、文件夹实例演示,scp命令的参数详解
- Oracle 数据库利用sql语句判断某个表是否是临时表实例演示,达梦数据库查询出所有临时表
- JavaScript 技术篇-一段js代码展示可以随鼠标移动变换样式的卡通人物,动态女生眼睛跟着鼠转动
- PyQt5 图形界面-用Qt Designer来设计UI界面,并转化为python代码运行