测试 Flask 应用

没有经过测试的东西都是不完整的

这一箴言的起源已经不可考了,尽管他不是完全正确的,但是仍然离真理不远。没有测试过的应用将会使得提高现有代码质量很困难,二不测试应用程序的开发者,会显得特别多疑。如果一个应用拥有自动化测试,那么您就可以安全的修改然后立刻知道是否有错误。

Flask 提供了一种方法用于测试您的应用,那就是将 Werkzeug 测试 Client 暴露出来,并且为您操作这些内容的本地上下文变量。然后您就可以将自己最喜欢的测试解决方案应用于其上了。 在这片文档中,我们将会使用Python自带的 unittest 包。

测试的大框架

为了测试这个引用,我们添加了第二个模块(flaskr_tests.py), 并且创建了一个框架如下:

import os
import flaskr
import unittest
import tempfile class FlaskrTestCase(unittest.TestCase): def setUp(self):
self.db_fd, flaskr.app.config['DATABASE'] = tempfile.mkstemp()
flaskr.app.config['TESTING'] = True
self.app = flaskr.app.test_client()
flaskr.init_db() def tearDown(self):
os.close(self.db_fd)
os.unlink(flaskr.app.config['DATABASE']) if __name__ == '__main__':
unittest.main()

  

setUp() 方法的代码创建了一个新的测试客户端并且初始化了一个新的数据库。这个函数将会在每次独立的测试函数运行之前运行。要在测试之后删除这个数据库,我们在 tearDown() 函数当中关闭这个文件,并将它从文件系统中删除。同时,在初始化的时候 TESTING 配置标志被激活,这将会使得处理请求时的错误捕捉失效,以便于您在进行对应用发出请求的测试时获得更好的错误反馈。

这个测试客户端将会给我们一个通向应用的简单接口,我们可以激发对向应用发送请求的测试,并且此客户端也会帮我们记录 Cookie 的动态。

因为 SQLite3 是基于文件系统的,我们可以很容易的使用临时文件模块来创建一个临时的数据库并初始化它,函数 mkstemp() 实际上完成了两件事情:它返回了一个底层的文件指针以及一个随机的文件名,后者我们用作数据库的名字。我们只需要将 db_fd 变量保存起来,就可以使用 os.close 方法来关闭这个文件。

如果我们运行这套测试,我们应该会得到如下的输出:

$ python flaskr_tests.py

----------------------------------------------------------------------
Ran 0 tests in 0.000s OK

虽然现在还未进行任何实际的测试,我们已经可以知道我们的 flaskr 程序没有语法错误了。否则,在 import 的时候就会抛出一个致死的错误了。

第一个测试

是进行第一个应用功能的测试的时候了。让我们检查当我们访问根路径(/)时应用程序是否正确地返回了了“No entries here so far” 字样。为此,我们添加了一个新的测试函数到我们的类当中, 如下面的代码所示:

class FlaskrTestCase(unittest.TestCase):

    def setUp(self):
self.db_fd, flaskr.app.config['DATABASE'] = tempfile.mkstemp()
self.app = flaskr.app.test_client()
flaskr.init_db() def tearDown(self):
os.close(self.db_fd)
os.unlink(flaskr.DATABASE) def test_empty_db(self):
rv = self.app.get('/')
assert 'No entries here so far' in rv.data

  

注意到我们的测试函数以 test 开头,这允许 unittest 模块自动识别出哪些方法是一个测试方法,并且运行它。

通过使用 self.app.get 我们可以发送一个 HTTP GET 请求给应用的某个给定路径。返回值将会是一个 response_class 对象。我们可以使用 data 属性来检查程序的返回值(以字符串类型)。在这里,我们检查 'No entries here so far' 是不是输出内容的一部分。

再次运行,您应该看到一个测试成功通过了:

$ python flaskr_tests.py
.
----------------------------------------------------------------------
Ran 1 test in 0.034s OK

登陆和登出

我们应用的大部分功能只允许具有管理员资格的用户访问。所以我们需要一种方法来帮助我们的测试客户端登陆和登出。为此,我们向登陆和登出页面发送一些请求,这些请求都携带了表单数据(用户名和密码),因为登陆和登出页面都会重定向,我们将客户端设置为 follow_redirects

将如下两个方法加入到您的 FlaskrTestCase 类:

 

现在我们可以轻松的测试登陆和登出是正常工作还是因认证失败而出错, 添加新的测试函数到类中:

def test_login_logout(self):
rv = self.login('admin', 'default')
assert 'You were logged in' in rv.data
rv = self.logout()
assert 'You were logged out' in rv.data
rv = self.login('adminx', 'default')
assert 'Invalid username' in rv.data
rv = self.login('admin', 'defaultx')
assert 'Invalid password' in rv.data

  

测试消息的添加

我们同时应该测试消息的添加功能是否正常,添加一个新的测试方法如下:

def test_messages(self):
self.login('admin', 'default')
rv = self.app.post('/add', data=dict(
title='<Hello>',
text='<strong>HTML</strong> allowed here'
), follow_redirects=True)
assert 'No entries here so far' not in rv.data
assert '<Hello>' in rv.data
assert '<strong>HTML</strong> allowed here' in rv.data

  

这里我们测试计划的行为是否能够正常工作,即在正文中可以出现 HTML 标签,而在标题中不允许。

运行这个测试,我们应该得到三个通过的测试:

$ python flaskr_tests.py
...
----------------------------------------------------------------------
Ran 3 tests in 0.332s OK

关于请求的头信息和状态值等更复杂的测试,请参考 MiniTwit Example ,在这个例子的源代码里包含一套更长的测试。

其他测试技巧

除了如上文演示的使用测试客户端完成测试的方法,也有一个 test_request_context() 方法可以配合 with 语句用于激活一个临时的请求上下文。通过它,您可以访问 requestgsession 类的对象,就像在视图中一样。 这里有一个完整的例子示范了这种用法:

app = flask.Flask(__name__)

with app.test_request_context('/?name=Peter'):
assert flask.request.path == '/'
assert flask.request.args['name'] == 'Peter'

  

所有其他的和上下文绑定的对象都可以使用同样的方法访问。

如果您希望测试应用在不同配置的情况下的表现,这里似乎没有一个很好的方法,考虑使用应用的工厂函数(参考 应用程序的工厂函数)

注意,尽管你在使用一个测试用的请求环境,函数 before_request() 以及 after_request() 都不会自动运行。 然而,teardown_request() 函数在测试请求的上下文离开 with 块的时候会执行。如果您希望 before_request() 函数仍然执行。 您需要手动调用 preprocess_request() 方法:

app = flask.Flask(__name__)

with app.test_request_context('/?name=Peter'):
app.preprocess_request()
...

这对于打开数据库连接或者其他类似的操作来说,很可能是必须的,这视您应用的设计方式而定。

如果您希望调用 after_request() 函数, 您需要使用 process_response() 方法。 这个方法需要您传入一个 response 对象:

app = flask.Flask(__name__)

with app.test_request_context('/?name=Peter'):
resp = Response('...')
resp = app.process_response(resp)
...

这通常不是很有效,因为这时您可以直接转向使用测试客户端。

伪造资源和上下文

0.10 新版功能.

在应用上下文或 flask.g 对象上存储用户认证信息和数据库连接非常常见。一般的模式是在第一次使用对象时,把对象放在应用上下文或 flask.g 上面,而在请求销毁时移除对象。试想一下例如下面的获取当前用户的代码:

def get_user():
user = getattr(g, 'user', None)
if user is None:
user = fetch_current_user_from_database()
g.user = user
return user

对于测试,这样易于从外部覆盖这个用户,而不用修改代码。连接 flask.appcontext_pushed 信号可以很容易地完成这个任务:

from contextlib import contextmanager
from flask import appcontext_pushed @contextmanager
def user_set(app, user):
def handler(sender, **kwargs):
g.user = user
with appcontext_pushed.connected_to(handler, app):
yield

并且之后使用它:

from flask import json, jsonify

@app.route('/users/me')
def users_me():
return jsonify(username=g.user.username) with user_set(app, my_user):
with app.test_client() as c:
resp = c.get('/users/me')
data = json.loads(resp.data)
self.assert_equal(data['username'], my_user.username)

保存上下文

0.4 新版功能.

有时,激发一个通常的请求,但是将当前的上下文保存更长的时间,以便于附加的内省发生是很有用的。 在 Flask 0.4 中,通过 test_client() 函数和 with 块的使用可以实现:

app = flask.Flask(__name__)

with app.test_client() as c:
rv = c.get('/?tequila=42')
assert request.args['tequila'] == ''

如果您仅仅使用 test_client() 方法,而不使用 with 代码块, assert 断言会失败,因为 request 不再可访问(因为您试图在非真正请求中时候访问它)。

访问和修改 Sessions

0.8 新版功能.

有时,在测试客户端里访问和修改 Sesstions 可能会非常有用。 通常有两种方法实现这种需求。如果您仅仅希望确保一个 Session 拥有某个特定的键,且此键的值是某个特定的值,那么您可以只保存起上下文,并且访问 flask.session:

with app.test_client() as c:
rv = c.get('/')
assert flask.session['foo'] == 42

但是这样做并不能使您修改 Session 或在请求发出之前访问 Session。 从 Flask 0.8 开始,我们提供一个叫做 “Session 事务” 的东西用于模拟适当的调用,从而在测试客户端的上下文中打开一个 Session,并用于修改。在事务的结尾,Session 将被恢复为原来的样子。这些都独立于 Session 的后端使用:

with app.test_client() as c:
with c.session_transaction() as sess:
sess['a_key'] = 'a value' # once this is reached the session was stored

注意到,在此时,您必须使用这个 sess 对象而不是调用 flask.session 代理,而这个对象本身提供了同样的接口。

转:http://docs.jinkan.org/docs/flask/testing.html

测试 Flask 应用的更多相关文章

  1. windows下测试flask的例子tuorial报错flask KeyError: 'DATABASE'

    windows下测试flask的例子tuorial报错flask KeyError: 'DATABASE' flask KeyError: 'DATABASE' 提示是 变量 database错误 由 ...

  2. jmeter测试 flask 接口请求

    jmeter测试 flask 接口请求 flask的代码如下: #!/usr/bin/env python # -*- coding: utf-8 -*- from flask import Flas ...

  3. 测试Flask应用_学习笔记

    源代码尽在我的github上面:https://github.com/521xueweihan 欢迎大家交流学习 """ setUp() 方法中会创建一个新的测试客户端并 ...

  4. 测试Flask+PYTHON的WEB框架

    参数URL: http://blog.csdn.net/qwiwuqo/article/details/8970621 安装flask之前,你必须要先安装python和easy_install. 安装 ...

  5. python unittest 测试笔记(二):使用Requests

    1. Requests 唯一的一个非转基因的 Python HTTP 库,人类可以安全享用.[Python Requests快速入门 :]http://cn.python-requests.org/z ...

  6. Python Flask框架

    Python有很多Web框架,可谓是百家争鸣,我这里列出几个比较叼的几个框架 Django      市场占有率最高,官方文档几近完美,但是适合比较大的项目,小项目会显得累赘. Tornado    ...

  7. 解决从pip上下载的最新flask版本不能运行flaskr和最新特性的问题

    由于在测试flask的单元测试.所以准备弄个环境,查询官方文档发现flask源码里面有一个example文件夹里面有个flaskr应用 可供测试 看了一下readme文档,大致是这样 / Flaskr ...

  8. 欢迎使用 Flask¶

    欢迎使用 Flask¶ 欢迎阅读 Flask 文档. 本文档分为几个部分.我推荐您先从 安装 开始,之后再浏览 快速入门 章节. 教程 比快速入门更详细地介绍了如何用 Flask 创建一个完整的 应用 ...

  9. 欢迎来到 Flask 的世界

    欢迎来到 Flask 的世界 欢迎阅读 Flask 的文档.本文档分成几个部分,我推荐您先读 < 安装 >,然后读< 快速上手 >.< 教程 > 比快速上手文档更详 ...

随机推荐

  1. 【代码笔记】Web-Javascript-Javascript typeof

    一,效果图. 二,代码. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> ...

  2. Python基础知识点

    自学记录: 1.字符串 python中单引号和双引号使用完全相同. 使用三引号('''或""")可以指定一个多行字符串. 转义符 '\' 反斜杠可以用来转义,使用r可以让 ...

  3. 调用Android自带浏览器打开网页

    转载请注明出处: http://blog.csdn.net/lowprofile_coding/article/details/77928608 在Android中可以调用自带的浏览器,或者指定一个浏 ...

  4. Spark操作HBase报:org.apache.hadoop.hbase.client.RetriesExhaustedWithDetailsException异常解决方案

    一.异常信息 19/03/21 15:01:52 WARN scheduler.TaskSetManager: Lost task 4.0 in stage 21.0 (TID 14640, hnte ...

  5. PHP的匿名函数和闭包

    匿名函数 // Example1 $func = function( $param ) { echo $param; }; $func( 'some string' );//输出:some strin ...

  6. DPA从DPA 10.0.352升级到DPA 11.0.373

    1: 解压安装文件SolarWinds-DPA-11.0.373-64bit.tar.gz [root@lnxmonitor tmp]# tar -xzvf SolarWinds-DPA-11.0.3 ...

  7. 批量配置SSH互信脚本

    在大规模自动化部署时我们常常需要配置好服务器的SSH互信,以便自动化脚本可以免密登录远程服务器,常规的手动配置SSH互信步骤如下: 使用ssh-keygen生成本地ssh key(mha01),生成的 ...

  8. Win10 C盘桌面文件右上方的两个蓝色箭头解决方案

    之前看网上有很多桌面蓝色箭头的解决方案,也进行了一些尝试 可是每次Win10系统更新之后蓝色箭头就会重新显示. 最终方案:将建立在桌面的C盘文件移到D盘,桌面创建对应的快捷方式. 一劳永逸,暴力破解.

  9. win8.1安装win64_11gR2_database_2of2 【INS-13001]】环境不满足最低要求问题

    1. 如图问题: 2. 修改 database\stage\cvu\cvu_prereq.xml, 添加windows 8.1 <OPERATING_SYSTEM RELEASE="6 ...

  10. 【PAT】B1007 素数对猜想

    素数筛筛出规定范围内的所有素数存入数组 遍历数组,如果满足于后边的差2,计数器加加 #include <cstdio> const int maxn = 10000001; int pri ...