测试 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. linux下允许和禁止root远程登录的方法

    1.vi /etc/ssh/sshd_config,将PermitRootLogin的值改成yes,并保存 PermitRootLogin yes 另外需要添加 AllowUsers root SA ...

  2. Offer选择与总结

    今天是2015.11.23,我估计这也是继高考.保研这些决定与选择之后,又一个比较重大的人生选择.最终选择了去微信支付,按钱来说比最高的offer少五万,其实挺心疼的.但是从发展和部门核心程度来讲,应 ...

  3. 3款网页jQuery抽奖实例演示

    实例演示 实例演示 实例演示

  4. C# 添加Windows服务,定时任务。

    源码下载地址:http://files.cnblogs.com/files/lanyubaicl/20160830Windows%E6%9C%8D%E5%8A%A1.zip 步骤 一 . 创建服务项目 ...

  5. HTML 请求头,响应头和 HTTP状态码

    请求头 选项 说明 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8 告诉服务器,当前客户端可以接收的文档类型 ...

  6. cf1121F. Compress String(后缀自动机)

    题意 题目链接 Sol 居然出个SAM板子也是没谁了233 #include<bits/stdc++.h> #define Pair pair<int, int> #defin ...

  7. 转载:使用redis+flask维护动态代理池

    githu源码地址:https://github.com/Germey/ProxyPool更好的代理池维护:https://github.com/Python3WebSpider/ProxyPool ...

  8. matlab练习程序(地图上画经纬度)

    需要看下生成的数据在地球上的经纬度具体位置. 投影为墨卡托投影.   clear all; close all; clc; load coast; a=load('out.txt'); %自己的经纬度 ...

  9. java--反射机制总结

    一.什么是Java反射机制? JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法:这种动态获取的以及动态调用对象的方法的功能 ...

  10. pyHook和pythoncom的安装

    pyHook包为Windows中的全局鼠标和键盘事件提供回调.Python应用程序为用户输入事件注册事件处理程序,例如鼠标左键,鼠标左键,按键等,并设置键盘和/或鼠标挂钩.底层C库报告的信息包括事件的 ...