Flask 测试
测试是每个应用系统发布前必须经历的步骤,自动化测试对测试效率的提高也是毋庸置疑的。对于Flask应用来说,当然可以使用Web自动化测试工具,比如Selenium等来测。Flask官方推荐的自动化测试方法是一种白盒测试,它依赖于Werkzeug的Client对象来模拟客户端。使用这个方法的好处是你不需要真的运行一个应用实例,也不依赖于任何浏览器。而测试框架就使用Python中的unittest包,对于大家上手也方便。
Set Up和Tear Down方法
Set Up方法会在每个测试用例执行前被调用,一般用来初始化测试用例的运行环境,而Tear Down方法会在每个测试用例执行完后被调用,一般用来销毁该测试用例的运行环境。这样做,就可以保证测试用例之间互相不影响。让我们先创建一个测试代码文件,并写入测试类,及Set Up和Tear Down方法:
import os
import unittest
import tempfile
import sqlite3
from contextlib import closing
from flask6 import app class SampleTestCase(unittest.TestCase): def setUp(self):
self.db_fd, app.config['DATABASE'] = tempfile.mkstemp()
app.config['TESTING'] = True
self.init_db(app.config['DATABASE']) def tearDown(self):
os.close(self.db_fd)
os.unlink(app.config['DATABASE']) def init_db(self, db_file):
with closing(sqlite3.connect(db_file)) as db:
with app.open_resource('init.sql', mode='r') as f:
db.cursor().executescript(f.read())
db.commit() if __name__ == '__main__':
unittest.main()
上述代码中,”flask6″就是我们要测试的应用。测试类”SampleTestCase”继承了”unittest.TestCase”类。我们在其”setUp()”方法中,创建了一个临时的sqlite3数据库文件,并将其初始化,同时我们将应用配置项”TESTING”设置为True,表示使用测试模式。在测试类的”tearDown()”方法中,我们销毁了之前创建的临时数据库文件,因此它不会影响下一个测试用例。执行测试的方法就是”unittest.main()”。
创建测试用例
下面是一个测试用户成功登录的测试用例,”setUp()”和”tearDown()”方法我们就略去了:
from flask import session class SampleTestCase(unittest.TestCase):
# setUp() and tearDown() here... # Test case
def test_valid_login(self):
with app.test_client() as client:
response = client.post('/login', data=dict(
user='admin',
passwd=''
), follow_redirects=True)
assert 'Login successfully' in response.data
assert session['user'] == 'admin'
测试用例函数都是以”test”开头,这样unittest包会自动识别其为一个测试用例。在测试用例函数中,我们先使用”app.test_client()”来获取一个”werkzeug.test.Client”类型的对象来模拟客户端。此后我们就可以通过”client.get(url)”或”client.post(url)”来模拟发送GET或POST请求了。”get()”或”post()”方法的”data”参数可以传入请求所需要的参数,它是一个字典;”follow_redirects”参数为True时,请求函数(即视图函数)内的”redirect()”重定向才有效。因为我们的login成功后会redirect到index页面,所以这个参数必须设为True。请求返回Response对象,你可以使用response.data获取响应体的内容。
假设测试的代码写在了”sample_test.py”,我们可以执行python命令:
python sample_test.py
整个函数都在”with app.test_client() as client”语句体内。朋友们可能会问,为什么不把这个client的初始化写在”setUp()”方法里,这样省去每个测试函数都要写一遍的麻烦。其实这个with语句有一个作用,就是语句块内可以访问请求上下文,所以上例中可以获取session对象的内容。离开with语句,request和session对象都无法获取
修改会话session
上面的测试用例中,我们成功将admin用户登录,所以session中的user值为admin。如果这时我们想修改这个值,怎么做?笨办法是先登出,再换个用户登录。Flask其实提供了方法让我们修改当前测试用例中的session值。我们在上面的测试用例函数中,加上下一段代码:
# Modify session
with client.session_transaction() as sess:
sess['user'] = 'guest' # Request home page
response = client.get('/', follow_redirects=True)
assert 'Hello guest' in response.data
assert session['user'] == 'guest'
我们通过”client.session_transaction()”方法来获取可以被修改的session,然后将其”user”字段改为”guest”。此后的请求中session中的”user”值就变为了”guest”。
构建请求上下文
有时候我们不想模拟客户端访问一个已有的URL来创建请求。我们想创建一个虚拟的请求,并且建立虚拟的请求上下文环境,看看下面的例子:
from flask import make_response, render_template, request class SampleTestCase(unittest.TestCase):
# setUp() and tearDown() here... # Test case
def test_home_with_context(self):
with app.test_request_context('/?user=admin'):
assert request.path == '/'
assert request.args['user'] == 'admin'
response = make_response(render_template('hello.html',
name=request.args['user']))
assert 'Hello admin' in response.data
这里,我们使用”with app.test_request_context()”语句构建了一个虚拟的”/?user=admin”请求上下文环境,因此我们可以在其中访问到请求对象request。在使用”with app.test_request_context()”时,离开with语句会调用上下文Hook函数”teardown_request()”,但是”before_request()”和”after_request()”的Hook函数都不会被调用。你必须使用”app.preprocess_request()”和”app.process_response()”来显式地调用它们,比如基于上面的例子,我们可以这样调用”before_request()”和”after_request()”的上下文Hook函数:
def test_home_with_context(self):
with app.test_request_context('/?user=admin'):
# All before_request hooks will be called here
app.preprocess_request()
assert request.path == '/'
assert request.args['user'] == 'admin'
response = make_response(render_template('hello.html',
name=request.args['user']))
assert 'Hello admin' in response.data
# All after_request hooks will be called here
response = app.process_response(response)
设置应用上下文
如果我们想往应用上下文添加或修改内容呢?方法是定义你要修改应用上下文的函数,并将它作为订阅”appcontext_pushed”信号的回调函数。这样,函数会在应用上下文压入栈时被执行。
from contextlib import contextmanager
from flask import appcontext_pushed, g @contextmanager
def name_set(app, name):
def handler(sender, **kwargs):
g.app_name = name
with appcontext_pushed.connected_to(handler, app):
yield
“@contextmanager”装饰器表明可以针对”name_set()”函数使用with语句来限制其上下文作用域,即离开了”with name_set()”语句块后,”appcontext_pushed”信号的订阅就无效了。现在我们可以在测试用例中这样使用这个”name_set()”函数:
from contextlib import contextmanager
from flask import appcontext_pushed, g class SampleTestCase(unittest.TestCase):
# setUp() and tearDown() here... # Test case
def test_update_app_context(self):
with name_set(app, 'Sample'):
with app.test_client() as client:
response = client.get('/app')
assert 'Sample' in response.data
上例中,在请求”/app”的视图函数里,”g.app_name”的值即被设为”Sample”.
Flask 测试的更多相关文章
- Flask测试和部署
一 蓝图Blueprint 为什么学习蓝图? 我们学习Flask框架,是从写单个文件,执行hello world开始的.我们在这单个文件中可以定义路由.视图函数.定义模型等等.但这显然存在一个问题:随 ...
- azure flask 测试
本机 flask on linux service 完美.选择部署槽 web app service
- Flask 学习 十四 测试
获取代码覆盖报告 安装代码覆盖工具 pip install coverage manage.py 覆盖检测 COV = None if os.environ.get('FLASK_COVERAGE') ...
- flask客户端测试使用设置cookie参数
今天在对flask客户端进行测试,然后看到我们服务器端用请求前钩子写了这样的代码 @app.before_requestdef before_request(): session = request. ...
- Windows下快速安装Flask的一次经历
前提: 1.已安装python版本(一般都是2.X) 2.已安装easy_install python安装,记得配置Python的环境变量,例如:我的直接在Path上加 G:\Python 验证安装P ...
- python常用web框架性能测试(django,flask,bottle,tornado)
测了一下django.flask.bottle.tornado 框架本身最简单的性能.对django的性能完全无语了. django.flask.bottle 均使用gunicorn+gevent启动 ...
- Flask:使用Eclipse+PyDev插件编辑基于package的项目
Windows 10家庭中文版,Python 3.6.4,Flask 1.0.2,Eclipse Oxygen.1a Release (4.7.1a),PyDev 6.3.2 本文记录了 使用Ecli ...
- 部署flas到服务器:No module named flask
首先,你要先把nginx和uwsgi安装好(个人觉得这搭起来比较舒服),可以通过pip 或者源安装,具体方法在前面我有提到过,好了接下来我就讲讲我的踩坑经历与解决办法. 我先采用的pip insta ...
- FlaskWeb开发:基于Python的Web应用开发实战
所属网站分类: 资源下载 > python电子书 作者:熊猫烧香 链接:http://www.pythonheidong.com/blog/article/63/ 来源:python黑洞网,专注 ...
随机推荐
- css边框小结
css边框 CSS对界面的分割如上图,他们的含义如下: contend:包含HTML元素中包含的文本,图像或其他媒体. padding:内容和边框之间的空格. 你可以想像这样的内在空间. ...
- javascript 推箱子游戏介绍及问题
最近没什么事情,我的一个亲戚在学校学习PHP,课程中老师让他们编写一个javascript版本的推箱子小游戏,他没什么头绪,就来问我,我当时很闲,就随口答应他包在我身上.结果真正写的时候还是花了点时间 ...
- Docker(二):Dockerfile 使用介绍
上一篇文章Docker(一):Docker入门教程介绍了 Docker 基本概念,其中镜像.容器和 Dockerfile .我们使用 Dockerfile 定义镜像,依赖镜像来运行容器,因此 Dock ...
- Sharepoint对List增删改操作
在sharepoint的开发过程中,用得最多的,就是获取sharepoint的列表数据,以及对其进行一系列的增删改查等操作,这里主要是记录一些常用的操作,通过对象模型方式对数据进行增删改查. 由于sh ...
- WebCracker4.0和monster字典——路由器登陆密码破解工具
路由器登陆密码破解,很伤cpu的
- Facebook兆级别图片存储及每秒百万级别图片查询原理
前言 Facebook(后面简称fb)是世界最大的社交平台,需要存储的数据时刻都在不断剧增(占比最大为图片,每天存储约20亿张,大概是微信的三倍). 那么问题来了,fb是如何存储兆级别的图片?并且又是 ...
- linux下Tomcat 安装后执行startup.sh,出现– Cannot find …bin/catalina.sh
linux下Tomcat 安装后执行startup.sh,出现– Cannot find …bin/catalina.sh 是因为权限不够,执行以下命令就可以: chmod +x startup.sh ...
- unix命令
最近需要用到一些Unix的东西 ,就学习了下这个东西,简单记录下命令,方便以后查询! 1. ls这是最基本的档案指令. ls 的意义为 "list",也就是将某一个目录或是某一个档 ...
- 面向服务的体系架构 SOA(三) --- Zookeeper API、zkClient API的使用
zookeeper简单介绍及API使用 1.1 zookeeper简介 zookeeper是一个针对大型分布式系统的可靠的协调系统,提供的功能包括配置维护.名字服务.分布式同步.组服务等.zookee ...
- 在使用document.getElementById('xxx').files[0]时,关于计算图片大小
在使用文件上传属性时,一直好奇图片上传的大小时如何计算的,最近在使用中认识到的计算方式: 首先,图片大小的存储基本单位是字节(byte).每个字节是由8个比特(bit)组成.所以,一个字节在十进制中 ...